From dc009c3fb0082ebfbbc53645a14f22516ceafe35 Mon Sep 17 00:00:00 2001 From: Ross Schulman Date: Mon, 21 Dec 2020 10:57:49 -0500 Subject: [PATCH 1/7] Create some fundamentals for gui management and partial completion of Computer GUI --- build.gradle | 2 +- gradle.properties | 2 +- src/main/kotlin/li/cli/oc/Components.kt | 25 +- src/main/kotlin/li/cli/oc/Config.kt | 80 ++ src/main/kotlin/li/cli/oc/OpenComputers.kt | 20 + .../kotlin/li/cli/oc/blockentity/Screen.kt | 273 ++++++ .../cli/oc/blockentity/commons/TextBuffer.kt | 855 ++++++++++++++++++ src/main/kotlin/li/cli/oc/blocks/Cable.kt | 2 - src/main/kotlin/li/cli/oc/blocks/Case.kt | 34 +- src/main/kotlin/li/cli/oc/blocks/Screen.kt | 24 +- .../cli/oc/blocks/commons/BakedModelConfig.kt | 39 +- .../oc/blocks/commons/RedstoneAwareEntity.kt | 9 +- .../li/cli/oc/blocks/commons/TecBlock.kt | 11 +- .../kotlin/li/cli/oc/client/ClientInit.kt | 11 + .../li/cli/oc/client/gui/blocks/CaseScreen.kt | 57 ++ .../oc/client/gui/blocks/CaseScreenHandler.kt | 36 + .../cli/oc/client/gui/blocks/slots/CPUSlot.kt | 18 + .../oc/client/gui/blocks/slots/EEPROMSlot.kt | 16 + .../cli/oc/client/gui/blocks/slots/ExpSlot.kt | 17 + .../cli/oc/client/gui/blocks/slots/HDSlot.kt | 17 + .../cli/oc/client/gui/blocks/slots/RAMSlot.kt | 17 + src/main/kotlin/li/cli/oc/items/CPU.kt | 9 + .../kotlin/li/cli/oc/render/block/Screen.kt | 163 ++++ .../kotlin/li/cli/oc/tileentity/Screen.kt | 18 - src/main/resources/fabric.mod.json | 2 +- 25 files changed, 1706 insertions(+), 51 deletions(-) create mode 100644 src/main/kotlin/li/cli/oc/Config.kt create mode 100644 src/main/kotlin/li/cli/oc/blockentity/Screen.kt create mode 100644 src/main/kotlin/li/cli/oc/blockentity/commons/TextBuffer.kt create mode 100644 src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt create mode 100644 src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt create mode 100644 src/main/kotlin/li/cli/oc/client/gui/blocks/slots/CPUSlot.kt create mode 100644 src/main/kotlin/li/cli/oc/client/gui/blocks/slots/EEPROMSlot.kt create mode 100644 src/main/kotlin/li/cli/oc/client/gui/blocks/slots/ExpSlot.kt create mode 100644 src/main/kotlin/li/cli/oc/client/gui/blocks/slots/HDSlot.kt create mode 100644 src/main/kotlin/li/cli/oc/client/gui/blocks/slots/RAMSlot.kt create mode 100644 src/main/kotlin/li/cli/oc/items/CPU.kt create mode 100644 src/main/kotlin/li/cli/oc/render/block/Screen.kt delete mode 100644 src/main/kotlin/li/cli/oc/tileentity/Screen.kt diff --git a/build.gradle b/build.gradle index 5abcb0c317..56a56af122 100644 --- a/build.gradle +++ b/build.gradle @@ -27,10 +27,10 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + modImplementation "net.fabricmc:fabric-language-kotlin:${project.fabric_kotlin_version}" include "net.fabricmc:fabric-language-kotlin:${project.fabric_kotlin_version}" - include "me.shedaniel.cloth:config-2:4.8.3" } processResources { diff --git a/gradle.properties b/gradle.properties index 943936d002..0677f5394d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,4 @@ kotlin.code.style=official loom_version=0.5-SNAPSHOT # Kotlin kotlin_version=1.4.0 - fabric_kotlin_version=1.4.0+build.1 \ No newline at end of file + fabric_kotlin_version=1.4.21+build.1 \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/Components.kt b/src/main/kotlin/li/cli/oc/Components.kt index 1a9314ddde..c8a62bf7e8 100644 --- a/src/main/kotlin/li/cli/oc/Components.kt +++ b/src/main/kotlin/li/cli/oc/Components.kt @@ -1,13 +1,19 @@ package li.cli.oc import li.cli.oc.blocks.* +import li.cli.oc.client.gui.blocks.CaseScreen +import li.cli.oc.client.gui.blocks.CaseScreenHandler import li.cli.oc.items.Analyzer import li.cli.oc.items.commons.ComponentBlockItem import li.cli.oc.items.commons.ComponentItem +import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings +import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry import net.minecraft.block.Block +import net.minecraft.block.Material import net.minecraft.block.entity.BlockEntity import net.minecraft.block.entity.BlockEntityType import net.minecraft.item.Item +import net.minecraft.screen.ScreenHandlerType import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import java.util.function.Supplier @@ -21,9 +27,9 @@ object Components { } enum class BlockEntities(val id: String, val entityType: BlockEntityType) { - ScreenOne("screen1", makeType({ li.cli.oc.tileentity.Screen(1) }, Blocks.ScreenOne.block)), - ScreenTwo("screen2", makeType({ li.cli.oc.tileentity.Screen(2) }, Blocks.ScreenTwo.block)), - ScreenThree("screen3", makeType({ li.cli.oc.tileentity.Screen(3) }, Blocks.ScreenThree.block)) + ScreenOne("screen1", makeType({ li.cli.oc.blockentity.Screen(1) }, Blocks.ScreenOne.block)), + ScreenTwo("screen2", makeType({ li.cli.oc.blockentity.Screen(2) }, Blocks.ScreenTwo.block)), + ScreenThree("screen3", makeType({ li.cli.oc.blockentity.Screen(3) }, Blocks.ScreenThree.block)) } enum class Blocks(val id: String, val block: Block) { @@ -32,10 +38,10 @@ object Components { Cable("cable", Cable()), Capacitor("capacitor", Capacitor()), CarpatedCapacitor("carpetedcapacitor", CarpetedCapacitor()), - CaseOne("case1", Case(1)), - CaseTwo("case2", Case(2)), - CaseThree("case3", Case(3)), - CaseCreative("casecreative", Case(4)), + CaseOne("case1", Case(1, FabricBlockSettings.of(Material.METAL).nonOpaque())), + CaseTwo("case2", Case(2, FabricBlockSettings.of(Material.METAL).nonOpaque())), + CaseThree("case3", Case(3, FabricBlockSettings.of(Material.METAL).nonOpaque())), + CaseCreative("casecreative", Case(4, FabricBlockSettings.of(Material.METAL).nonOpaque())), Charger("charger", Charger()), Disassembler("disassembler", Disassembler()), DiskDrive("diskdrive", DiskDrive()), @@ -176,7 +182,7 @@ object Components { fun registerComponents() { caseEntityType = Registry.register(Registry.BLOCK_ENTITY_TYPE, Identifier(OpenComputers.modId, "case"), - BlockEntityType.Builder.create({ CaseEntity() }, Case(4)).build(null)) + BlockEntityType.Builder.create({ CaseEntity() }, Case(4, FabricBlockSettings.of(Material.METAL).nonOpaque())).build(null)) BlockEntities.values().iterator().forEach { x -> Registry.register(Registry.BLOCK_ENTITY_TYPE, Identifier(OpenComputers.modId, x.id), x.entityType) @@ -191,5 +197,8 @@ object Components { } } + val CASE1 = Case(1, FabricBlockSettings.of(Material.METAL).nonOpaque(), ) + val CASE_SCREEN_HANDLER: ScreenHandlerType = ScreenHandlerRegistry.registerSimple(Identifier(OpenComputers.modId, "case1"), ::CaseScreenHandler) + } diff --git a/src/main/kotlin/li/cli/oc/Config.kt b/src/main/kotlin/li/cli/oc/Config.kt new file mode 100644 index 0000000000..f2f40985ba --- /dev/null +++ b/src/main/kotlin/li/cli/oc/Config.kt @@ -0,0 +1,80 @@ +package li.cli.oc + +import net.fabricmc.loader.api.FabricLoader +import java.io.File +import java.io.IOException + +import java.io.FileWriter + +import java.io.FileNotFoundException + +import java.io.FileReader + +import java.io.BufferedReader + +object ConfigLoader { + + private var file: File? = null; + private var config: Config? = null; + + fun prepareConfigFile() { + if (file != null) + return; + file = File(FabricLoader.getInstance().configDir.toString(), OpenComputers.modId + ".json") + } + + fun initializeConfig(): Config { + if (config != null) return config!!; + + config = Config(); + load(); + + return config!!; + } + private fun load() { + prepareConfigFile() + try { + if (file?.exists() == false) { + save() + } + if (file?.exists() == true) { + val br = BufferedReader(FileReader(file)) + val parsed = OpenComputers.GSON.fromJson(br, Config::class.java) + if (parsed != null) { + config = parsed + } + } + } catch (e: FileNotFoundException) { + System.err.println("Couldn't load OpenComputers configuration file; reverting to defaults") + e.printStackTrace() + } + } + + fun save() { + prepareConfigFile() + val jsonString = OpenComputers.GSON.toJson(config) + try { + FileWriter(file).use { fileWriter -> fileWriter.write(jsonString) } + } catch (e: IOException) { + System.err.println("Couldn't save OpenComputers configuration file") + e.printStackTrace() + } + } + + fun getConfig(): Config { + return config ?: Config() + } +} + +data class EnergieCost(val screen: Double = 0.05) + +data class MultiBlocks( + val screenHeight: Int = 6, + val screenWidth: Int = 8 +) + +data class Config( + val energieCost: EnergieCost = EnergieCost(), + val multiBlocks: MultiBlocks = MultiBlocks() +) + diff --git a/src/main/kotlin/li/cli/oc/OpenComputers.kt b/src/main/kotlin/li/cli/oc/OpenComputers.kt index 3ef0338b59..8d720a3632 100644 --- a/src/main/kotlin/li/cli/oc/OpenComputers.kt +++ b/src/main/kotlin/li/cli/oc/OpenComputers.kt @@ -1,10 +1,24 @@ package li.cli.oc +import com.google.gson.JsonDeserializer import net.fabricmc.api.ModInitializer import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder +import net.fabricmc.loader.api.FabricLoader import net.minecraft.block.Blocks +import net.minecraft.client.MinecraftClient import net.minecraft.item.ItemStack import net.minecraft.util.Identifier +import net.minecraft.util.JsonSerializer +import java.io.File +import java.nio.charset.Charset +import com.google.gson.FieldNamingPolicy + +import com.google.gson.GsonBuilder + +import com.google.gson.Gson + + + object OpenComputers: ModInitializer { @@ -12,7 +26,13 @@ object OpenComputers: ModInitializer { val ITEM_GROUP = FabricItemGroupBuilder.build(Identifier(modId, "general")) { ItemStack(Blocks.NETHERITE_BLOCK) } + val GSON = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.IDENTITY).setPrettyPrinting().create() + override fun onInitialize() { + ConfigLoader.initializeConfig() + println(if (ConfigLoader.getConfig()?.energieCost?.screen != null) "OpenComputers config loaded" else "Failed to load OpenComputers") Components.registerComponents() } + + } diff --git a/src/main/kotlin/li/cli/oc/blockentity/Screen.kt b/src/main/kotlin/li/cli/oc/blockentity/Screen.kt new file mode 100644 index 0000000000..654ee593f1 --- /dev/null +++ b/src/main/kotlin/li/cli/oc/blockentity/Screen.kt @@ -0,0 +1,273 @@ +package li.cli.oc.blockentity + +import li.cli.oc.Components +import net.minecraft.block.entity.BlockEntity +import net.minecraft.block.entity.BlockEntityType +import net.minecraft.nbt.CompoundTag +import net.minecraft.block.BlockState +import net.minecraft.util.Tickable +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import java.util.* +import li.cli.oc.ConfigLoader +import li.cli.oc.blockentity.commons.TextBuffer +import li.cli.oc.blocks.commons.States +import li.cli.oc.render.Color +import li.cli.oc.render.block.Flags + + +private fun getEntityFromTier(Tier: Int): BlockEntityType { + return when(Tier) { + 1 -> Components.BlockEntities.ScreenOne.entityType + 2 -> Components.BlockEntities.ScreenTwo.entityType + 3 -> Components.BlockEntities.ScreenThree.entityType + else -> null!! + } +} + +class Screen(val tier: Int): BlockEntity(getEntityFromTier(tier)), Tickable { + + var address: UUID? = null + var textBuffer: TextBuffer? = null + var width = 1 + var height = 1 + var offsetX = 0 + var offsetY = 0 + var removeState = false + var notifying = false + + var connectedAt: Int? = null + + override fun tick() { + // soon + } + + fun getColor(): Int { + return Color.getTearColors(tier - 1) + } + + fun notifyOthers() { + notifying = true + + if (offsetX > 0) getNeighbour(offsetX - 1, offsetY)?.notifySelf() + if (offsetX + 1 < height) getNeighbour(offsetX + 1, offsetY)?.notifySelf() + if (offsetY > 0) getNeighbour(offsetX, offsetY - 1)?.notifySelf() + if (offsetY + 1 < height) getNeighbour(offsetX, offsetY + 1)?.notifySelf() + + notifying = false + } + + fun notifySelf() { + val origin = getOrigin() + if (origin == null) { + val right = if (width > 1) getNeighbour(1, 0) else null + val below = if (height > 1) getNeighbour(0, 1) else null + right?.resize(width - 1, 1) + below?.resize(width, height - 1) + right?.expand() + below?.expand() + return + } + + for (y in 0 until height) { + for (x in 0 until width) { + val monitor = origin.getNeighbour(x, y) + if (monitor != null) continue + + var above: Screen? = null + var left: Screen? = null + var right: Screen? = null + var below: Screen? = null + if (y > 0) { + above = origin + above.resize(width, y) + } + if (x > 0) { + left = origin.getNeighbour(0, y) + left?.resize(x, 1) + } + if (x + 1 < width) { + right = origin.getNeighbour(x + 1, y) + right?.resize(width - (x + 1), 1) + } + if (y + 1 < height) { + below = origin.getNeighbour(0, y + 1) + below?.resize(width, height - (y + 1)) + } + above?.expand() + left?.expand() + right?.expand() + below?.expand() + return + } + } + } + + private fun mergeLeft(): Boolean { + val left = getNeighbour(-1, 0) + if (left == null || left.offsetY != 0 || left.height != height) return false + val width = left.width + width + + if (width > ConfigLoader.getConfig()!!.multiBlocks.screenWidth) return false + left.getOrigin()?.resize(width, height) + left.expand() + return true + } + + private fun mergeRight(): Boolean { + val right = getNeighbour(width, 0) + if (right == null || right.offsetY != 0 || right.height != height) return false + val width = width + right.width + + if (width > ConfigLoader.getConfig()!!.multiBlocks.screenWidth) return false + getOrigin()?.resize(width, height) + expand() + return true + } + + private fun mergeUp(): Boolean { + val above = getNeighbour(0, height) + if (above == null || above.offsetX != 0 || above.width != width) return false + val height: Int = above.height + height + if (height > ConfigLoader.getConfig()?.multiBlocks!!.screenHeight) return false + getOrigin()?.resize(width, height) + expand() + return true + } + + private fun mergeDown(): Boolean { + val below= getNeighbour(0, -1) + if (below == null || below.offsetX != 0 || below.width != width) return false + val height = height + below.height + if (height > ConfigLoader.getConfig()?.multiBlocks!!.screenHeight) return false + below.getOrigin()?.resize(width, height) + below.expand() + return true + } + + fun expand() { + while (mergeLeft() || mergeRight() || mergeUp() || mergeDown()) { } + } + private fun resize(width: Int, height: Int) { + if (offsetX != 0 || offsetY != 0) textBuffer = null + offsetX = 0 + offsetY = 0 + this.width = width + this.height = height + + textBuffer = if(textBuffer == null) TextBuffer() else null + + + // textBuffer?.setResolution() + + for (x in 0 until width) { + for (y in 0 until height) { + val monitor = getNeighbour(x, y) ?: continue + monitor.offsetX = x + monitor.offsetY = y + monitor.width = width + monitor.height = height + monitor.textBuffer = textBuffer + monitor.updateBlockState() + monitor.updateBlock() + } + } + } + override fun toTag(tag: CompoundTag): CompoundTag { + super.toTag(tag) + if(address != null) tag.putUuid("address", address) + tag.putInt("width", width) + tag.putInt("height", height) + tag.putInt("offsetX", offsetX) + tag.putInt("offsetY", offsetY) + if(connectedAt != null) tag.putInt("screenConnect", connectedAt!!) + return tag + } + + override fun fromTag(state: BlockState?, tag: CompoundTag) { + super.fromTag(state,tag) + address = tag.getUuid("address") + + val oldOffsetX = offsetX + val oldOffsetY = offsetY + val oldWidth = width + val oldHeight = height + + width = tag.getInt("width") + height = tag.getInt("height") + offsetX = tag.getInt("offsetX") + offsetY = tag.getInt("offsetY") + connectedAt = tag.getInt("screenConnect") + + if (offsetX != offsetX || offsetY != offsetY) { + // if (oldOffsetX == 0 && oldOffsetY == 0 && textBuffer != null) textBuffer.destroy() + textBuffer = null + } + + if (offsetX == 0 && offsetY == 0 && textBuffer == null) + textBuffer = TextBuffer() + + if (oldOffsetX != offsetX || oldOffsetY != offsetY || oldWidth != width || oldHeight != height) + updateBlock() + + } + + fun getNeighbour(x: Int, y: Int): Screen? { + + val xOffset = -offsetX + x + val yOffset = -offsetY + y + try { + return getSimilarMonitorAt(pos.offset(getRight(), xOffset).offset(getDown(), yOffset)) + } catch(e: NullPointerException) { + return null + } + } + + private fun getOrigin(): Screen? { return getNeighbour(0, 0) } + + private fun getSimilarMonitorAt(pos: BlockPos): Screen? { + if (pos == getPos()) return this + val world = getWorld() + if (world == null || !world.isRegionLoaded(pos, pos)) return null + + val tile: Screen? = world.getBlockEntity(pos) as? Screen + val monitor = tile as Screen + return if ( + !monitor.notifying + && !monitor.removeState + && tier == monitor.tier + && getBlockYaw() === monitor.getBlockYaw() + && getBlockPitch() === monitor.getBlockPitch() + ) monitor else null + } + + private fun updateBlockState() { + connectedAt = Flags.from(offsetY < height - 1, offsetY > 0, offsetX > 0, offsetX < width - 1) + } + + private fun updateBlock() { + markDirty() + val state: BlockState = world!!.getBlockState(pos) + world!!.updateListeners(pos, state, state, 3) + } + + fun getBlockYaw(): Direction { + val state: BlockState = world!!.getBlockState(pos) + return state.get(States.Yaw) ?: Direction.NORTH + } + + fun getBlockPitch(): Direction { + val state: BlockState = world!!.getBlockState(pos) + return state.get(States.Pitch) ?: Direction.NORTH + } + + fun getRight(): Direction? { + return getBlockYaw().rotateYCounterclockwise() + } + + fun getDown(): Direction? { + if (getBlockPitch() == Direction.NORTH) return Direction.UP + return if (getBlockPitch() == Direction.DOWN) getBlockYaw() else getBlockYaw().opposite + } + +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/blockentity/commons/TextBuffer.kt b/src/main/kotlin/li/cli/oc/blockentity/commons/TextBuffer.kt new file mode 100644 index 0000000000..5ab1b4f7d2 --- /dev/null +++ b/src/main/kotlin/li/cli/oc/blockentity/commons/TextBuffer.kt @@ -0,0 +1,855 @@ +package li.cli.oc.blockentity.commons + +class TextBuffer() { + +// private var maxResolution: (Int, Int) = Settings.screenResolutionsByTier(Tier.One) +// +// private var maxDepth = Settings.screenDepthsByTier(Tier.One) +// +// private var aspectRatio = (1.0, 1.0) +// +// private var powerConsumptionPerTick = Settings.get.screenCost +// +// private var precisionMode = false +// +// // For client side only. +// private var isRendering = true +// +// private var isDisplaying = true +// +// private var hasPower = true +// +// private var relativeLitArea = -1.0 +// +// private var _pendingCommands: Option[PacketBuilder] = None +// +// private val syncInterval = 100 +// +// private var syncCooldown = syncInterval +// +// private def pendingCommands = _pendingCommands.getOrElse { +// val pb = new CompressedPacketBuilder(PacketType.TextBufferMulti) +// pb.writeUTF(node.address) +// _pendingCommands = Some(pb) +// pb +// } +// +// var fullyLitCost: Double = computeFullyLitCost() +// +// // This computes the energy cost (per tick) to keep the screen running if +// // every single "pixel" is lit. This cost increases with higher tiers as +// // their maximum resolution (pixel density) increases. For a basic screen +// // this is simply the configured cost. +// def computeFullyLitCost(): Double = { +// val (w, h) = Settings.screenResolutionsByTier(0) +// val mw = getMaximumWidth +// val mh = getMaximumHeight +// powerConsumptionPerTick * (mw * mh) / (w * h) +// } +// +// val proxy: TextBuffer.Proxy = +// if (SideTracker.isClient) new TextBuffer.ClientProxy(this) +// else new TextBuffer.ServerProxy(this) +// +// val data = new util.TextBuffer(maxResolution, PackedColor.Depth.format(maxDepth)) +// +// var viewport: (Int, Int) = data.size +// +// def markInitialized(): Unit = { +// syncCooldown = -1 // Stop polling for init state. +// relativeLitArea = -1 // Recompute lit area, avoid screens blanking out until something changes. +// } +// +// private final lazy val deviceInfo = Map( +// DeviceAttribute.Class -> DeviceClass.Display, +// DeviceAttribute.Description -> "Text buffer", +// DeviceAttribute.Vendor -> Constants.DeviceInfo.DefaultVendor, +// DeviceAttribute.Product -> "Text Screen V0", +// DeviceAttribute.Capacity -> (maxResolution._1 * maxResolution._2).toString, +// DeviceAttribute.Width -> Array("1", "4", "8").apply(maxDepth.ordinal()) +// ) +// +// override def getDeviceInfo: java.util.Map[String, String] = deviceInfo +// +// // ----------------------------------------------------------------------- // +// +// override val canUpdate = true +// +// override def update() { +// super.update() +// if (isDisplaying && host.world.getTotalWorldTime % Settings.get.tickFrequency == 0) { +// if (relativeLitArea < 0) { +// // The relative lit area is the number of pixels that are not blank +// // versus the number of pixels in the *current* resolution. This is +// // scaled to multi-block screens, since we only compute this for the +// // origin. +// val w = getViewportWidth +// val h = getViewportHeight +// var acc = 0f +// for (y <- 0 until h) { +// val line = data.buffer(y) +// val colors = data.color(y) +// for (x <- 0 until w) { +// val char = line(x) +// val color = colors(x) +// val bg = PackedColor.unpackBackground(color, data.format) +// val fg = PackedColor.unpackForeground(color, data.format) +// acc += (if (char == ' ') if (bg == 0) 0 else 1 +// else if (char == 0x2588) if (fg == 0) 0 else 1 +// else if (fg == 0 && bg == 0) 0 else 1) +// } +// } +// relativeLitArea = acc / (w * h).toDouble +// } +// if (node != null) { +// val hadPower = hasPower +// val neededPower = relativeLitArea * fullyLitCost * Settings.get.tickFrequency +// hasPower = node.tryChangeBuffer(-neededPower) +// if (hasPower != hadPower) { +// ServerPacketSender.sendTextBufferPowerChange(node.address, isDisplaying && hasPower, host) +// } +// } +// } +// +// this.synchronized { +// _pendingCommands.foreach(_.sendToPlayersNearHost(host, Option(Settings.get.maxWirelessRange(Tier.Two) * Settings.get.maxWirelessRange(Tier.Two)))) +// _pendingCommands = None +// } +// +// if (SideTracker.isClient && syncCooldown > 0) { +// syncCooldown -= 1 +// if (syncCooldown == 0) { +// syncCooldown = syncInterval +// ClientPacketSender.sendTextBufferInit(proxy.nodeAddress) +// } +// } +// } +// +// // ----------------------------------------------------------------------- // +// +// @Callback(direct = true, doc = """function():boolean -- Returns whether the screen is currently on.""") +// def isOn(computer: Context, args: Arguments): Array[AnyRef] = result(isDisplaying) +// +// @Callback(doc = """function():boolean -- Turns the screen on. Returns true if it was off.""") +// def turnOn(computer: Context, args: Arguments): Array[AnyRef] = { +// val oldPowerState = isDisplaying +// setPowerState(value = true) +// result(isDisplaying != oldPowerState, isDisplaying) +// } +// +// @Callback(doc = """function():boolean -- Turns off the screen. Returns true if it was on.""") +// def turnOff(computer: Context, args: Arguments): Array[AnyRef] = { +// val oldPowerState = isDisplaying +// setPowerState(value = false) +// result(isDisplaying != oldPowerState, isDisplaying) +// } +// +// @Callback(direct = true, doc = """function():number, number -- The aspect ratio of the screen. For multi-block screens this is the number of blocks, horizontal and vertical.""") +// def getAspectRatio(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { +// result(aspectRatio._1, aspectRatio._2) +// } +// +// @Callback(doc = """function():table -- The list of keyboards attached to the screen.""") +// def getKeyboards(context: Context, args: Arguments): Array[AnyRef] = { +// context.pause(0.25) +// host match { +// case screen: tileentity.Screen => +// Array(screen.screens.map(_.node).flatMap(_.neighbors.filter(_.host.isInstanceOf[Keyboard]).map(_.address)).toArray) +// case _ => +// Array(node.neighbors.filter(_.host.isInstanceOf[Keyboard]).map(_.address).toArray) +// } +// } +// +// @Callback(direct = true, doc = """function():boolean -- Returns whether the screen is in high precision mode (sub-pixel mouse event positions).""") +// def isPrecise(computer: Context, args: Arguments): Array[AnyRef] = result(precisionMode) +// +// @Callback(doc = """function(enabled:boolean):boolean -- Set whether to use high precision mode (sub-pixel mouse event positions).""") +// def setPrecise(computer: Context, args: Arguments): Array[AnyRef] = { +// // Available for T3 screens only... easiest way to check for us is to +// // base it off of the maximum color depth. +// if (maxDepth == Settings.screenDepthsByTier(Tier.Three)) { +// val oldValue = precisionMode +// precisionMode = args.checkBoolean(0) +// result(oldValue) +// } +// else result(Unit, "unsupported operation") +// } +// +// // ----------------------------------------------------------------------- // +// +// override def setEnergyCostPerTick(value: Double) { +// powerConsumptionPerTick = value +// fullyLitCost = computeFullyLitCost() +// } +// +// override def getEnergyCostPerTick: Double = powerConsumptionPerTick +// +// override def setPowerState(value: Boolean) { +// if (isDisplaying != value) { +// isDisplaying = value +// if (isDisplaying) { +// val neededPower = fullyLitCost * Settings.get.tickFrequency +// hasPower = node.changeBuffer(-neededPower) == 0 +// } +// ServerPacketSender.sendTextBufferPowerChange(node.address, isDisplaying && hasPower, host) +// } +// } +// +// override def getPowerState: Boolean = isDisplaying +// +// override def setMaximumResolution(width: Int, height: Int) { +// if (width < 1) throw new IllegalArgumentException("width must be larger or equal to one") +// if (height < 1) throw new IllegalArgumentException("height must be larger or equal to one") +// maxResolution = (width, height) +// fullyLitCost = computeFullyLitCost() +// proxy.onBufferMaxResolutionChange(width, width) +// } +// +// override def getMaximumWidth: Int = maxResolution._1 +// +// override def getMaximumHeight: Int = maxResolution._2 +// +// override def setAspectRatio(width: Double, height: Double): Unit = this.synchronized(aspectRatio = (width, height)) +// +// override def getAspectRatio: Double = aspectRatio._1 / aspectRatio._2 +// +// override def setResolution(w: Int, h: Int): Boolean = { +// val (mw, mh) = maxResolution +// if (w < 1 || h < 1 || w > mw || h > mw || h * w > mw * mh) +// throw new IllegalArgumentException("unsupported resolution") +// // Always send to clients, their state might be dirty. +// proxy.onBufferResolutionChange(w, h) +// // Force set viewport to new resolution. This is partially for +// // backwards compatibility, and partially to enforce a valid one. +// val sizeChanged = data.size = (w, h) +// val viewportChanged = setViewport(w, h) +// if (sizeChanged || viewportChanged) { +// if (!viewportChanged && node != null) { +// node.sendToReachable("computer.signal", "screen_resized", Int.box(w), Int.box(h)) +// } +// true +// } +// else false +// } +// +// override def setViewport(w: Int, h: Int): Boolean = { +// val (mw, mh) = data.size +// if (w < 1 || h < 1 || w > mw || h > mh) +// throw new IllegalArgumentException("unsupported viewport resolution") +// // Always send to clients, their state might be dirty. +// proxy.onBufferViewportResolutionChange(w, h) +// val (cw, ch) = viewport +// if (w != cw || h != ch) { +// viewport = (w, h) +// if (node != null) { +// node.sendToReachable("computer.signal", "screen_resized", Int.box(w), Int.box(h)) +// } +// true +// } +// else false +// } +// +// override def getViewportWidth: Int = viewport._1 +// +// override def getViewportHeight: Int = viewport._2 +// +// override def setMaximumColorDepth(depth: api.internal.TextBuffer.ColorDepth): Unit = maxDepth = depth +// +// override def getMaximumColorDepth: api.internal.TextBuffer.ColorDepth = maxDepth +// +// override def setColorDepth(depth: api.internal.TextBuffer.ColorDepth): Boolean = { +// val colorDepthChanged: Boolean = super.setColorDepth(depth) +// // Always send to clients, their state might be dirty. +// proxy.onBufferDepthChange(depth) +// colorDepthChanged +// } +// +// override def onBufferPaletteChange(index: Int): Unit = +// proxy.onBufferPaletteChange(index) +// +// override def onBufferColorChange(): Unit = +// proxy.onBufferColorChange() +// +// override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int): Unit = { +// proxy.onBufferCopy(col, row, w, h, tx, ty) +// } +// +// override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char): Unit = { +// proxy.onBufferFill(col, row, w, h, c) +// } +// +// override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean): Unit = { +// proxy.onBufferSet(col, row, s, vertical) +// } +// +// override def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, ram: component.GpuTextBuffer, fromCol: Int, fromRow: Int): Unit = { +// proxy.onBufferBitBlt(col, row, w, h, ram, fromCol, fromRow) +// } +// +// override def onBufferRamInit(ram: component.GpuTextBuffer): Unit = { +// proxy.onBufferRamInit(ram) +// } +// +// override def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = { +// proxy.onBufferRamDestroy(ram) +// } +// +// override def rawSetText(col: Int, row: Int, text: Array[Array[Char]]): Unit = { +// super.rawSetText(col, row, text) +// proxy.onBufferRawSetText(col, row, text) +// } +// +// override def rawSetBackground(col: Int, row: Int, color: Array[Array[Int]]): Unit = { +// super.rawSetBackground(col, row, color) +// // Better for bandwidth to send packed shorts here. Would need a special case for handling on client, +// // though, so let's be wasteful for once... +// proxy.onBufferRawSetBackground(col, row, color) +// } +// +// override def rawSetForeground(col: Int, row: Int, color: Array[Array[Int]]): Unit = { +// super.rawSetForeground(col, row, color) +// // Better for bandwidth to send packed shorts here. Would need a special case for handling on client, +// // though, so let's be wasteful for once... +// proxy.onBufferRawSetForeground(col, row, color) +// } +// +// @SideOnly(Side.CLIENT) +// override def renderText: Boolean = relativeLitArea != 0 && proxy.render() +// +// @SideOnly(Side.CLIENT) +// override def renderWidth: Int = TextBufferRenderCache.renderer.charRenderWidth * getViewportWidth +// +// @SideOnly(Side.CLIENT) +// override def renderHeight: Int = TextBufferRenderCache.renderer.charRenderHeight * getViewportHeight +// +// @SideOnly(Side.CLIENT) +// override def setRenderingEnabled(enabled: Boolean): Unit = isRendering = enabled +// +// @SideOnly(Side.CLIENT) +// override def isRenderingEnabled: Boolean = isRendering +// +// override def keyDown(character: Char, code: Int, player: EntityPlayer): Unit = +// proxy.keyDown(character, code, player) +// +// override def keyUp(character: Char, code: Int, player: EntityPlayer): Unit = +// proxy.keyUp(character, code, player) +// +// override def clipboard(value: String, player: EntityPlayer): Unit = +// proxy.clipboard(value, player) +// +// override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer): Unit = +// proxy.mouseDown(x, y, button, player) +// +// override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer): Unit = +// proxy.mouseDrag(x, y, button, player) +// +// override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer): Unit = +// proxy.mouseUp(x, y, button, player) +// +// override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit = +// proxy.mouseScroll(x, y, delta, player) +// +// def copyToAnalyzer(line: Int, player: EntityPlayer): Unit = { +// proxy.copyToAnalyzer(line, player) +// } +// +// // ----------------------------------------------------------------------- // +// +// override def onConnect(node: Node) { +// super.onConnect(node) +// if (node == this.node) { +// ServerComponentTracker.add(host.world, node.address, this) +// } +// } +// +// override def onDisconnect(node: Node) { +// super.onDisconnect(node) +// if (node == this.node) { +// ServerComponentTracker.remove(host.world, this) +// } +// } +// +// // ----------------------------------------------------------------------- // +// +// private def bufferPath = node.address + "_buffer" +// private final val IsOnTag = Settings.namespace + "isOn" +// private final val HasPowerTag = Settings.namespace + "hasPower" +// private final val MaxWidthTag = Settings.namespace + "maxWidth" +// private final val MaxHeightTag = Settings.namespace + "maxHeight" +// private final val PreciseTag = Settings.namespace + "precise" +// private final val ViewportWidthTag = Settings.namespace + "viewportWidth" +// private final val ViewportHeightTag = Settings.namespace + "viewportHeight" +// +// override def load(nbt: NBTTagCompound) { +// super.load(nbt) +// if (SideTracker.isClient) { +// if (!Strings.isNullOrEmpty(proxy.nodeAddress)) return // Only load once. +// proxy.nodeAddress = nbt.getCompoundTag(NodeData.NodeTag).getString(NodeData.AddressTag) +// TextBuffer.registerClientBuffer(this) +// } +// else { +// if (nbt.hasKey(NodeData.BufferTag)) { +// data.load(nbt.getCompoundTag(NodeData.BufferTag)) +// } +// else if (!Strings.isNullOrEmpty(node.address)) { +// data.load(SaveHandler.loadNBT(nbt, bufferPath)) +// } +// } +// +// if (nbt.hasKey(IsOnTag)) { +// isDisplaying = nbt.getBoolean(IsOnTag) +// } +// if (nbt.hasKey(HasPowerTag)) { +// hasPower = nbt.getBoolean(HasPowerTag) +// } +// if (nbt.hasKey(MaxWidthTag) && nbt.hasKey(MaxHeightTag)) { +// val maxWidth = nbt.getInteger(MaxWidthTag) +// val maxHeight = nbt.getInteger(MaxHeightTag) +// maxResolution = (maxWidth, maxHeight) +// } +// precisionMode = nbt.getBoolean(PreciseTag) +// +// if (nbt.hasKey(ViewportWidthTag)) { +// val vpw = nbt.getInteger(ViewportWidthTag) +// val vph = nbt.getInteger(ViewportHeightTag) +// viewport = (vpw min data.width max 1, vph min data.height max 1) +// } else { +// viewport = data.size +// } +// } +// +// // Null check for Waila (and other mods that may call this client side). +// override def save(nbt: NBTTagCompound): Unit = if (node != null) { +// super.save(nbt) +// // Happy thread synchronization hack! Here's the problem: GPUs allow direct +// // calls for modifying screens to give a more responsive experience. This +// // causes the following problem: when saving, if the screen is saved first, +// // then the executor runs in parallel and changes the screen *before* the +// // server thread begins saving that computer, the saved computer will think +// // it changed the screen, although the saved screen wasn't. To avoid that we +// // wait for all computers the screen is connected to to finish their current +// // execution and pausing them (which will make them resume in the next tick +// // when their update() runs). +// if (node.network != null) { +// for (node <- node.network.nodes) node.host match { +// case computer: tileentity.traits.Computer if !computer.machine.isPaused => +// computer.machine.pause(0.1) +// case _ => +// } +// } +// +// SaveHandler.scheduleSave(host, nbt, bufferPath, data.save _) +// nbt.setBoolean(IsOnTag, isDisplaying) +// nbt.setBoolean(HasPowerTag, hasPower) +// nbt.setInteger(MaxWidthTag, maxResolution._1) +// nbt.setInteger(MaxHeightTag, maxResolution._2) +// nbt.setBoolean(PreciseTag, precisionMode) +// nbt.setInteger(ViewportWidthTag, viewport._1) +// nbt.setInteger(ViewportHeightTag, viewport._2) +// } +//} +// +//object TextBuffer { +// var clientBuffers = mutable.ListBuffer.empty[TextBuffer] +// +// @SubscribeEvent +// def onChunkUnload(e: ChunkEvent.Unload) { +// val chunk = e.getChunk +// clientBuffers = clientBuffers.filter(t => { +// val blockPos = BlockPosition(t.host) +// val keep = t.host.world != e.getWorld || !chunk.isAtLocation(blockPos.x >> 4, blockPos.z >> 4) +// if (!keep) { +// ClientComponentTracker.remove(t.host.world, t) +// } +// keep +// }) +// } +// +// @SubscribeEvent +// def onWorldUnload(e: WorldEvent.Unload) { +// clientBuffers = clientBuffers.filter(t => { +// val keep = t.host.world != e.getWorld +// if (!keep) { +// ClientComponentTracker.remove(t.host.world, t) +// } +// keep +// }) +// } +// +// def registerClientBuffer(t: TextBuffer) { +// ClientPacketSender.sendTextBufferInit(t.proxy.nodeAddress) +// ClientComponentTracker.add(t.host.world, t.proxy.nodeAddress, t) +// clientBuffers += t +// } +// +// abstract class Proxy { +// def owner: TextBuffer +// +// var dirty = false +// +// var nodeAddress = "" +// +// def markDirty() { +// dirty = true +// } +// +// def render() = false +// +// def onBufferColorChange(): Unit +// +// def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { +// owner.relativeLitArea = -1 +// } +// +// def onBufferDepthChange(depth: api.internal.TextBuffer.ColorDepth): Unit +// +// def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) { +// owner.relativeLitArea = -1 +// } +// +// def onBufferPaletteChange(index: Int): Unit +// +// def onBufferResolutionChange(w: Int, h: Int) { +// owner.relativeLitArea = -1 +// } +// +// def onBufferViewportResolutionChange(w: Int, h: Int) { +// owner.relativeLitArea = -1 +// } +// +// def onBufferMaxResolutionChange(w: Int, h: Int) { +// } +// +// def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) { +// owner.relativeLitArea = -1 +// } +// +// def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, ram: component.GpuTextBuffer, fromCol: Int, fromRow: Int): Unit = { +// owner.relativeLitArea = -1 +// } +// +// def onBufferRamInit(ram: component.GpuTextBuffer): Unit = { +// owner.relativeLitArea = -1 +// } +// +// def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = { +// owner.relativeLitArea = -1 +// } +// +// def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) { +// owner.relativeLitArea = -1 +// } +// +// def onBufferRawSetBackground(col: Int, row: Int, color: Array[Array[Int]]) { +// owner.relativeLitArea = -1 +// } +// +// def onBufferRawSetForeground(col: Int, row: Int, color: Array[Array[Int]]) { +// owner.relativeLitArea = -1 +// } +// +// def keyDown(character: Char, code: Int, player: EntityPlayer): Unit +// +// def keyUp(character: Char, code: Int, player: EntityPlayer): Unit +// +// def clipboard(value: String, player: EntityPlayer): Unit +// +// def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer): Unit +// +// def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer): Unit +// +// def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer): Unit +// +// def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit +// +// def copyToAnalyzer(line: Int, player: EntityPlayer): Unit +// } +// +// class ClientProxy(val owner: TextBuffer) extends Proxy { +// val renderer = new TextBufferRenderData { +// override def dirty = ClientProxy.this.dirty +// +// override def dirty_=(value: Boolean) = ClientProxy.this.dirty = value +// +// override def data = owner.data +// +// override def viewport: (Int, Int) = owner.viewport +// } +// +// override def render() = { +// val wasDirty = dirty +// TextBufferRenderCache.render(renderer) +// wasDirty +// } +// +// override def onBufferColorChange() { +// markDirty() +// } +// +// override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { +// super.onBufferCopy(col, row, w, h, tx, ty) +// markDirty() +// } +// +// override def onBufferDepthChange(depth: api.internal.TextBuffer.ColorDepth) { +// markDirty() +// } +// +// override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) { +// super.onBufferFill(col, row, w, h, c) +// markDirty() +// } +// +// override def onBufferPaletteChange(index: Int) { +// markDirty() +// } +// +// override def onBufferResolutionChange(w: Int, h: Int) { +// super.onBufferResolutionChange(w, h) +// markDirty() +// } +// +// override def onBufferViewportResolutionChange(w: Int, h: Int) { +// super.onBufferViewportResolutionChange(w, h) +// markDirty() +// } +// +// override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) { +// super.onBufferSet(col, row, s, vertical) +// markDirty() +// } +// +// override def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, ram: component.GpuTextBuffer, fromCol: Int, fromRow: Int): Unit = { +// super.onBufferBitBlt(col, row, w, h, ram, fromCol, fromRow) +// markDirty() +// } +// +// override def onBufferRamInit(ram: component.GpuTextBuffer): Unit = { +// super.onBufferRamInit(ram) +// } +// +// override def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = { +// super.onBufferRamDestroy(ram) +// } +// +// override def keyDown(character: Char, code: Int, player: EntityPlayer) { +// debug(s"{type = keyDown, char = $character, code = $code}") +// ClientPacketSender.sendKeyDown(nodeAddress, character, code) +// } +// +// override def keyUp(character: Char, code: Int, player: EntityPlayer) { +// debug(s"{type = keyUp, char = $character, code = $code}") +// ClientPacketSender.sendKeyUp(nodeAddress, character, code) +// } +// +// override def clipboard(value: String, player: EntityPlayer) { +// debug(s"{type = clipboard}") +// ClientPacketSender.sendClipboard(nodeAddress, value) +// } +// +// override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) { +// debug(s"{type = mouseDown, x = $x, y = $y, button = $button}") +// ClientPacketSender.sendMouseClick(nodeAddress, x, y, drag = false, button) +// } +// +// override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) { +// debug(s"{type = mouseDrag, x = $x, y = $y, button = $button}") +// ClientPacketSender.sendMouseClick(nodeAddress, x, y, drag = true, button) +// } +// +// override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) { +// debug(s"{type = mouseUp, x = $x, y = $y, button = $button}") +// ClientPacketSender.sendMouseUp(nodeAddress, x, y, button) +// } +// +// override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) { +// debug(s"{type = mouseScroll, x = $x, y = $y, delta = $delta}") +// ClientPacketSender.sendMouseScroll(nodeAddress, x, y, delta) +// } +// +// override def copyToAnalyzer(line: Int, player: EntityPlayer): Unit = { +// ClientPacketSender.sendCopyToAnalyzer(nodeAddress, line) +// } +// +// private lazy val Debugger = api.Items.get(Constants.ItemName.Debugger) +// +// private def debug(message: String) { +// if (Minecraft.getMinecraft != null && Minecraft.getMinecraft.player != null && api.Items.get(Minecraft.getMinecraft.player.getHeldItemMainhand) == Debugger) { +// OpenComputers.log.info(s"[NETWORK DEBUGGER] Sending packet to node $nodeAddress: " + message) +// } +// } +// } +// +// class ServerProxy(val owner: TextBuffer) extends Proxy { +// override def onBufferColorChange() { +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferColorChange(owner.pendingCommands, owner.data.foreground, owner.data.background)) +// } +// +// override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { +// super.onBufferCopy(col, row, w, h, tx, ty) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferCopy(owner.pendingCommands, col, row, w, h, tx, ty)) +// } +// +// override def onBufferDepthChange(depth: api.internal.TextBuffer.ColorDepth) { +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferDepthChange(owner.pendingCommands, depth)) +// } +// +// override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char) { +// super.onBufferFill(col, row, w, h, c) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferFill(owner.pendingCommands, col, row, w, h, c)) +// } +// +// override def onBufferPaletteChange(index: Int) { +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferPaletteChange(owner.pendingCommands, index, owner.getPaletteColor(index))) +// } +// +// override def onBufferResolutionChange(w: Int, h: Int) { +// super.onBufferResolutionChange(w, h) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferResolutionChange(owner.pendingCommands, w, h)) +// } +// +// override def onBufferViewportResolutionChange(w: Int, h: Int) { +// super.onBufferViewportResolutionChange(w, h) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferViewportResolutionChange(owner.pendingCommands, w, h)) +// } +// +// override def onBufferMaxResolutionChange(w: Int, h: Int) { +// if (owner.node.network != null) { +// super.onBufferMaxResolutionChange(w, h) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferMaxResolutionChange(owner.pendingCommands, w, h)) +// } +// } +// +// override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean) { +// super.onBufferSet(col, row, s, vertical) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferSet(owner.pendingCommands, col, row, s, vertical)) +// } +// +// override def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, ram: component.GpuTextBuffer, fromCol: Int, fromRow: Int): Unit = { +// super.onBufferBitBlt(col, row, w, h, ram, fromCol, fromRow) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferBitBlt(owner.pendingCommands, col, row, w, h, ram.owner, ram.id, fromCol, fromRow)) +// } +// +// override def onBufferRamInit(ram: component.GpuTextBuffer): Unit = { +// super.onBufferRamInit(ram) +// owner.host.markChanged() +// val nbt = new NBTTagCompound() +// ram.save(nbt) +// owner.synchronized(ServerPacketSender.appendTextBufferRamInit(owner.pendingCommands, ram.owner, ram.id, nbt)) +// } +// +// override def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = { +// super.onBufferRamDestroy(ram) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferRamDestroy(owner.pendingCommands, ram.owner, ram.id)) +// } +// +// override def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) { +// super.onBufferRawSetText(col, row, text) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferRawSetText(owner.pendingCommands, col, row, text)) +// } +// +// override def onBufferRawSetBackground(col: Int, row: Int, color: Array[Array[Int]]) { +// super.onBufferRawSetBackground(col, row, color) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferRawSetBackground(owner.pendingCommands, col, row, color)) +// } +// +// override def onBufferRawSetForeground(col: Int, row: Int, color: Array[Array[Int]]) { +// super.onBufferRawSetForeground(col, row, color) +// owner.host.markChanged() +// owner.synchronized(ServerPacketSender.appendTextBufferRawSetForeground(owner.pendingCommands, col, row, color)) +// } +// +// override def keyDown(character: Char, code: Int, player: EntityPlayer) { +// sendToKeyboards("keyboard.keyDown", player, Char.box(character), Int.box(code)) +// } +// +// override def keyUp(character: Char, code: Int, player: EntityPlayer) { +// sendToKeyboards("keyboard.keyUp", player, Char.box(character), Int.box(code)) +// } +// +// override def clipboard(value: String, player: EntityPlayer) { +// sendToKeyboards("keyboard.clipboard", player, value) +// } +// +// override def mouseDown(x: Double, y: Double, button: Int, player: EntityPlayer) { +// sendMouseEvent(player, "touch", x, y, button) +// } +// +// override def mouseDrag(x: Double, y: Double, button: Int, player: EntityPlayer) { +// sendMouseEvent(player, "drag", x, y, button) +// } +// +// override def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer) { +// sendMouseEvent(player, "drop", x, y, button) +// } +// +// override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) { +// sendMouseEvent(player, "scroll", x, y, delta) +// } +// +// override def copyToAnalyzer(line: Int, player: EntityPlayer): Unit = { +// val stack = player.getHeldItem(EnumHand.MAIN_HAND) +// if (!stack.isEmpty) { +// if (!stack.hasTagCompound) { +// stack.setTagCompound(new NBTTagCompound()) +// } +// stack.getTagCompound.removeTag(Settings.namespace + "clipboard") +// +// if (line >= 0 && line < owner.getViewportHeight) { +// val text = new String(owner.data.buffer(line)).trim +// if (!Strings.isNullOrEmpty(text)) { +// stack.getTagCompound.setString(Settings.namespace + "clipboard", text) +// } +// } +// +// if (stack.getTagCompound.hasNoTags) { +// stack.setTagCompound(null) +// } +// } +// } +// +// private def sendMouseEvent(player: EntityPlayer, name: String, x: Double, y: Double, data: Int) = { +// val args = mutable.ArrayBuffer.empty[AnyRef] +// +// args += player +// args += name +// if (owner.precisionMode) { +// args += Double.box(x) +// args += Double.box(y) +// } +// else { +// args += Int.box(x.toInt + 1) +// args += Int.box(y.toInt + 1) +// } +// args += Int.box(data) +// if (Settings.get.inputUsername) { +// args += player.getName +// } +// +// owner.node.sendToReachable("computer.checked_signal", args: _*) +// } +// +// private def sendToKeyboards(name: String, values: AnyRef*) { +// owner.host match { +// case screen: tileentity.Screen => +// screen.screens.foreach(_.node.sendToNeighbors(name, values: _*)) +// case _ => +// owner.node.sendToNeighbors(name, values: _*) +// } +// } +// } + +} diff --git a/src/main/kotlin/li/cli/oc/blocks/Cable.kt b/src/main/kotlin/li/cli/oc/blocks/Cable.kt index 0a614ec537..f7cf04ff51 100644 --- a/src/main/kotlin/li/cli/oc/blocks/Cable.kt +++ b/src/main/kotlin/li/cli/oc/blocks/Cable.kt @@ -21,8 +21,6 @@ import net.minecraft.world.BlockRenderView import java.util.* import java.util.function.Supplier import net.minecraft.client.texture.SpriteAtlasTexture -import net.minecraft.client.util.math.Vector4f -import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3i class CableModel : BakedModelConfig() { diff --git a/src/main/kotlin/li/cli/oc/blocks/Case.kt b/src/main/kotlin/li/cli/oc/blocks/Case.kt index 0d6cf46ad6..e3865d41da 100644 --- a/src/main/kotlin/li/cli/oc/blocks/Case.kt +++ b/src/main/kotlin/li/cli/oc/blocks/Case.kt @@ -3,21 +3,40 @@ package li.cli.oc.blocks; import li.cli.oc.Components import li.cli.oc.blocks.commons.TecBlock; import li.cli.oc.blocks.commons.RedstoneAwareEntity; +import li.cli.oc.client.gui.blocks.CaseScreenHandler import li.cli.oc.render.Color import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings import net.minecraft.block.* import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.player.PlayerInventory import net.minecraft.item.ItemPlacementContext +import net.minecraft.screen.NamedScreenHandlerFactory +import net.minecraft.screen.ScreenHandler import net.minecraft.state.StateManager import net.minecraft.state.property.BooleanProperty; +import net.minecraft.text.Text +import net.minecraft.text.TranslatableText +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.world.BlockView; +import net.minecraft.world.World -class CaseEntity : RedstoneAwareEntity(Components.caseEntityType) { +class CaseEntity : RedstoneAwareEntity(Components.caseEntityType), NamedScreenHandlerFactory { + override fun createMenu(syncId: Int, inv: PlayerInventory, player: PlayerEntity): ScreenHandler { + return CaseScreenHandler(syncId, inv) + } + + override fun getDisplayName(): Text { + return Text.of("Computer") + } } -class Case(var Tear: Int) : TecBlock(FabricBlockSettings.of(Material.METAL)) { +class Case(var Tear: Int, settings: Settings) : TecBlock(settings) { override fun getColor(): Int { @@ -48,4 +67,15 @@ class Case(var Tear: Int) : TecBlock(FabricBlockSettings.of(Material.METAL)) { override fun getRenderType(state: BlockState?): BlockRenderType { return BlockRenderType.MODEL; } + + override fun onUse(state: BlockState, world: World, pos: BlockPos?, player: PlayerEntity, hand: Hand?, hit: BlockHitResult?): ActionResult? { + // Open the case screen if we can + if (!world.isClient) { + val screenHandlerFactory = state.createScreenHandlerFactory(world, pos) + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory) + } + } + return ActionResult.SUCCESS + } } diff --git a/src/main/kotlin/li/cli/oc/blocks/Screen.kt b/src/main/kotlin/li/cli/oc/blocks/Screen.kt index c4a92df4c9..1d3584e57a 100644 --- a/src/main/kotlin/li/cli/oc/blocks/Screen.kt +++ b/src/main/kotlin/li/cli/oc/blocks/Screen.kt @@ -3,14 +3,18 @@ package li.cli.oc.blocks; import li.cli.oc.blocks.commons.TecBlock; import li.cli.oc.blocks.commons.States import li.cli.oc.render.Color -import li.cli.oc.tileentity.Screen +import li.cli.oc.blockentity.Screen import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings import net.minecraft.block.* import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.LivingEntity import net.minecraft.item.ItemPlacementContext +import net.minecraft.item.ItemStack import net.minecraft.state.StateManager +import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.world.BlockView; +import net.minecraft.world.World class Screen(var Tier: Int) : TecBlock(FabricBlockSettings.of(Material.METAL)) { @@ -27,7 +31,7 @@ class Screen(var Tier: Int) : TecBlock(FabricBlockSettings.of(Material.METAL)) { .with(yaw, States.Yaws[0]) } - override fun createBlockEntity(world: BlockView?): BlockEntity? { + override fun createBlockEntity(world: BlockView?): BlockEntity { return Screen(Tier); } @@ -46,4 +50,20 @@ class Screen(var Tier: Int) : TecBlock(FabricBlockSettings.of(Material.METAL)) { override fun getRenderType(state: BlockState?): BlockRenderType { return BlockRenderType.MODEL; } + + override fun onPlaced( + world: World?, + pos: BlockPos?, + state: BlockState?, + placer: LivingEntity?, + itemStack: ItemStack? + ) { + super.onPlaced(world, pos, state, placer, itemStack) + + val entity = world?.getBlockEntity(pos) as? Screen + + entity?.notifyOthers() + entity?.notifySelf() + entity?.expand() + } } diff --git a/src/main/kotlin/li/cli/oc/blocks/commons/BakedModelConfig.kt b/src/main/kotlin/li/cli/oc/blocks/commons/BakedModelConfig.kt index 359e19bb59..dcfd911749 100644 --- a/src/main/kotlin/li/cli/oc/blocks/commons/BakedModelConfig.kt +++ b/src/main/kotlin/li/cli/oc/blocks/commons/BakedModelConfig.kt @@ -10,6 +10,7 @@ import net.minecraft.client.render.model.json.ModelOverrideList import net.minecraft.client.render.model.json.ModelTransformation import net.minecraft.client.texture.Sprite import net.minecraft.client.util.SpriteIdentifier +import net.minecraft.client.util.math.Vector4f import net.minecraft.util.Identifier import net.minecraft.util.math.Direction import java.util.* @@ -29,11 +30,41 @@ abstract class BakedModelConfig: UnbakedModel, BakedModel, FabricBakedModel { ): Collection { return spriteIds.asList() } + fun renderSprite( + emitter: QuadEmitter?, + direction: Direction, + texture: Sprite?, + vector: Vector4f, + customRotation: Int = MutableQuadView.BAKE_LOCK_UV, + color: Int = -1 + ){ + renderSprite(emitter, + direction, + texture, + vector.x, + vector.y, + vector.z, + vector.w, + 0.0f, + customRotation, + color) + } - fun renderSprite(emitter: QuadEmitter?, direction: Direction, texture: Sprite?, left: Float, bottom: Float, right: Float, top: Float, depth: Float){ + fun renderSprite( + emitter: QuadEmitter?, + direction: Direction, + texture: Sprite?, + left: Float, + bottom: Float, + right: Float, + top: Float, + depth: Float, + customRotation: Int = MutableQuadView.BAKE_LOCK_UV, + color: Int = -1 + ){ emitter?.square(direction, left, bottom, right, top, depth) - emitter?.spriteBake(0, texture, MutableQuadView.BAKE_LOCK_UV) - emitter?.spriteColor(0, -1, -1, -1, -1) + emitter?.spriteBake(0, texture, customRotation) + emitter?.spriteColor(0, color,color, color, color) emitter?.emit() } @@ -44,7 +75,7 @@ abstract class BakedModelConfig: UnbakedModel, BakedModel, FabricBakedModel { modelId: Identifier? ): BakedModel? { - for (i in 0..1) { + for (i in spriteIds.indices) { sprites[i] = textureGetter?.apply(spriteIds[i]) } diff --git a/src/main/kotlin/li/cli/oc/blocks/commons/RedstoneAwareEntity.kt b/src/main/kotlin/li/cli/oc/blocks/commons/RedstoneAwareEntity.kt index 1862a2a559..2131387a28 100644 --- a/src/main/kotlin/li/cli/oc/blocks/commons/RedstoneAwareEntity.kt +++ b/src/main/kotlin/li/cli/oc/blocks/commons/RedstoneAwareEntity.kt @@ -1,7 +1,13 @@ package li.cli.oc.blocks.commons; +import li.cli.oc.client.gui.blocks.CaseScreenHandler import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.player.PlayerInventory +import net.minecraft.screen.NamedScreenHandlerFactory +import net.minecraft.screen.ScreenHandler +import net.minecraft.text.Text import net.minecraft.util.math.Direction; import java.util.* @@ -10,7 +16,6 @@ open class RedstoneAwareEntity(type: BlockEntityType<*>?) : BlockEntity(type) { // val input = Arrays.asList(-1, -1, -1, -1, -1, -1) val output = listOf(0, 0, 0, 0, 0, 0) - fun getOutput(direction: Direction): Int { for (i in 0..Direction.values().size) { @@ -18,6 +23,6 @@ open class RedstoneAwareEntity(type: BlockEntityType<*>?) : BlockEntity(type) { return output[i]; } } - return -1; + return 0; } } diff --git a/src/main/kotlin/li/cli/oc/blocks/commons/TecBlock.kt b/src/main/kotlin/li/cli/oc/blocks/commons/TecBlock.kt index 7515bd08ed..e858c9b7d3 100644 --- a/src/main/kotlin/li/cli/oc/blocks/commons/TecBlock.kt +++ b/src/main/kotlin/li/cli/oc/blocks/commons/TecBlock.kt @@ -17,22 +17,13 @@ open class TecBlock(settings: Settings?) : BlockWithEntity(settings) { } override fun emitsRedstonePower(state: BlockState?): Boolean { - return true; - } - - override fun getStrongRedstonePower(state: BlockState?, world: BlockView?, pos: BlockPos?, direction: Direction?): Int { - return getWeakRedstonePower(state, world, pos, direction) + return false; } override fun createBlockEntity(world: BlockView?): BlockEntity? { return null } - override fun getWeakRedstonePower(state: BlockState?, world: BlockView?, pos: BlockPos?, direction: Direction?): Int { - val entity = world!!.getBlockEntity(pos) as RedstoneAwareEntity; - return entity.getOutput(direction!!); - } - override fun getRenderType(state: BlockState?): BlockRenderType { return BlockRenderType.MODEL; } diff --git a/src/main/kotlin/li/cli/oc/client/ClientInit.kt b/src/main/kotlin/li/cli/oc/client/ClientInit.kt index b1cf4076c0..9b6a0d3e17 100644 --- a/src/main/kotlin/li/cli/oc/client/ClientInit.kt +++ b/src/main/kotlin/li/cli/oc/client/ClientInit.kt @@ -5,14 +5,21 @@ import li.cli.oc.OpenComputers import li.cli.oc.blocks.CableModel import li.cli.oc.blocks.Case import li.cli.oc.blocks.Screen +import li.cli.oc.client.gui.blocks.CaseScreen import li.cli.oc.items.commons.ComponentBlockItem import li.cli.oc.render.BaseModelProvider +import li.cli.oc.render.block.ScreenModel import net.fabricmc.api.ClientModInitializer import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry +import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry +import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry import net.minecraft.block.BlockState +import net.minecraft.block.entity.BlockEntity import net.minecraft.client.render.RenderLayer +import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher +import net.minecraft.client.render.block.entity.BlockEntityRenderer import net.minecraft.item.ItemStack import net.minecraft.util.Identifier import net.minecraft.util.math.BlockPos @@ -22,6 +29,8 @@ object ClientInit : ClientModInitializer { override fun onInitializeClient() { ModelLoadingRegistry.INSTANCE.registerResourceProvider { BaseModelProvider(Identifier(OpenComputers.modId, "block/cable"), CableModel()) } + ModelLoadingRegistry.INSTANCE.registerResourceProvider { BaseModelProvider(Identifier(OpenComputers.modId, "block/screen"), ScreenModel()) } + ColorProviderRegistry.BLOCK.register(handleBlockColor, Components.Blocks.CaseOne.block, @@ -44,6 +53,8 @@ object ClientInit : ClientModInitializer { ) BlockRenderLayerMap.INSTANCE.putBlock(Components.Blocks.Assembler.block, RenderLayer.getTranslucent()); + + ScreenRegistry.register(Components.CASE_SCREEN_HANDLER, ::CaseScreen) } private val handleItemColor = fun (item: ItemStack, tintIndex: Int): Int { diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt new file mode 100644 index 0000000000..f4ae19d38c --- /dev/null +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt @@ -0,0 +1,57 @@ +package li.cli.oc.client.gui.blocks + +import com.mojang.blaze3d.systems.RenderSystem +import li.cli.oc.OpenComputers +import net.minecraft.client.gui.screen.ingame.HandledScreen +import net.minecraft.client.gui.widget.TexturedButtonWidget +import net.minecraft.client.util.math.MatrixStack +import net.minecraft.entity.player.PlayerInventory +import net.minecraft.screen.ScreenHandler +import net.minecraft.text.Text +import net.minecraft.util.Identifier + +class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Text?) : HandledScreen(handler, inventory, title) { + + override fun drawBackground(matrices: MatrixStack?, delta: Float, mouseX: Int, mouseY: Int) { + RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f) + assert(client != null) + client!!.textureManager.bindTexture(TEXTURE) + val x = (width - backgroundWidth) / 2 + val y = (height - backgroundHeight) / 2 + drawTexture(matrices, x, y, 0, 0, backgroundWidth, backgroundHeight) + + client!!.textureManager.bindTexture(COMP_TEXTURE) + drawTexture(matrices, x, y + 1, 0, 0, 256, 256) + } + + + override fun render(matrices: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) { + renderBackground(matrices) + super.render(matrices, mouseX, mouseY, delta) + drawMouseoverTooltip(matrices, mouseX, mouseY) + } + + override fun init() { + super.init() + val x = (width - backgroundWidth) / 2 + val y = (height - backgroundHeight) / 2 + // Center the title + titleX = 7 + val powerButton = TexturedButtonWidget(x + (backgroundWidth / 2) - 18 , y + 34, 18, 18, 0, 0, 0, BUTTON_TEXTURE, 36, 36) { button -> + TODO( + "Computer start/stop here" + ) + } + addButton(powerButton) + + + } + + companion object { + private val TEXTURE = Identifier(OpenComputers.modId, "textures/gui/background.png") + private val COMP_TEXTURE = Identifier(OpenComputers.modId, "textures/gui/computer.png") + private val BUTTON_TEXTURE = Identifier(OpenComputers.modId, "textures/gui/button_power.png") + private val SLOT_TEXTURE = Identifier(OpenComputers.modId, "textures/gui/slot.png") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt new file mode 100644 index 0000000000..9f717b15cc --- /dev/null +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt @@ -0,0 +1,36 @@ +package li.cli.oc.client.gui.blocks + +import li.cli.oc.Components +import li.cli.oc.client.gui.blocks.slots.* +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.player.PlayerInventory +import net.minecraft.inventory.SimpleInventory +import net.minecraft.screen.ScreenHandler +import net.minecraft.screen.slot.Slot + +class CaseScreenHandler(syncId: Int, playerInventory: PlayerInventory) : ScreenHandler(Components.CASE_SCREEN_HANDLER, syncId) { + private val inventory = SimpleInventory(10) + + override fun canUse(player: PlayerEntity?): Boolean { + return inventory.canPlayerUse(player) + } + + init { + // BIOS Slot to the left of the power button + addSlot(Slot(inventory, 0, 20, 20)) + + // Two Expansion Slot Cards to the left of the component grid + addSlot(Slot(inventory, 1, 80, 10)) + addSlot(Slot(inventory, 2, 80, 30)) + + // One CPU Slot in the center top of the component grid + addSlot(Slot(inventory, 3, 100, 10)) + + // Two RAM Slots in the direct middle and bottom middle of the component grid + addSlot(Slot(inventory, 4, 100, 30)) + addSlot(Slot(inventory, 5, 100, 50)) + + // One HDD Slot in the top right of the component grid + addSlot(Slot(inventory, 6, 120, 10)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/CPUSlot.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/CPUSlot.kt new file mode 100644 index 0000000000..8fa131b8f9 --- /dev/null +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/CPUSlot.kt @@ -0,0 +1,18 @@ +package li.cli.oc.client.gui.blocks.slots + +import li.cli.oc.items.CPU +import net.minecraft.inventory.Inventory +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.Slot + +class CPUSlot(inventory: Inventory, index: Int, x: Int, y: Int, level: Int) : Slot(inventory, index, x, y) { + private val tier: Int = 0 + +/* override fun canInsert(stack: ItemStack?): Boolean { + if (stack != null) { + return stack.item is CPU && CPU.tier <= tier + } + + return false + }*/ +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/EEPROMSlot.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/EEPROMSlot.kt new file mode 100644 index 0000000000..5fbde4a600 --- /dev/null +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/EEPROMSlot.kt @@ -0,0 +1,16 @@ +package li.cli.oc.client.gui.blocks.slots + +import net.minecraft.inventory.Inventory +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.Slot + +class EEPROMSlot(inventory: Inventory, index: Int, x: Int, y: Int) : Slot(inventory, index, x, y) { + +/* override fun canInsert(stack: ItemStack?): Boolean { + if (stack != null) { + return stack.item is EEPROM // TODO: Rename once BIOS Card item class is created + } + + return false + }*/ +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/ExpSlot.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/ExpSlot.kt new file mode 100644 index 0000000000..e68d480bf8 --- /dev/null +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/ExpSlot.kt @@ -0,0 +1,17 @@ +package li.cli.oc.client.gui.blocks.slots + +import net.minecraft.inventory.Inventory +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.Slot + +class ExpSlot(inventory: Inventory, index: Int, x: Int, y: Int, level: Int) : Slot(inventory, index, x, y) { + private val level: Int = 0 + +/* override fun canInsert(stack: ItemStack?): Boolean { + if (stack != null) { + return stack.item is ExpansionCard && ExpansionCard.level <= level// TODO: Rename once Expansion Card item class is created + } + + return false + }*/ +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/HDSlot.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/HDSlot.kt new file mode 100644 index 0000000000..b210da3bce --- /dev/null +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/HDSlot.kt @@ -0,0 +1,17 @@ +package li.cli.oc.client.gui.blocks.slots + +import net.minecraft.inventory.Inventory +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.Slot + +class HDSlot(inventory: Inventory, index: Int, x: Int, y: Int, level: Int) : Slot(inventory, index, x, y) { + private val level: Int = 0 + +/* override fun canInsert(stack: ItemStack?): Boolean { + if (stack != null) { + return stack.item is HardDrive && HardDrive.level <= level// TODO: Rename once Expansion Card item class is created + } + + return false + }*/ +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/RAMSlot.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/RAMSlot.kt new file mode 100644 index 0000000000..f3de09ac61 --- /dev/null +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/slots/RAMSlot.kt @@ -0,0 +1,17 @@ +package li.cli.oc.client.gui.blocks.slots + +import net.minecraft.inventory.Inventory +import net.minecraft.item.ItemStack +import net.minecraft.screen.slot.Slot + +class RAMSlot(inventory: Inventory, index: Int, x: Int, y: Int, level: Int) : Slot(inventory, index, x, y) { + private val level: Int = 0 + +/* override fun canInsert(stack: ItemStack?): Boolean { + if (stack != null) { + return stack.item is RAMCard && RAMCard.level <= level// TODO: Rename once RAM Card item class is created + } + + return false + }*/ +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/items/CPU.kt b/src/main/kotlin/li/cli/oc/items/CPU.kt new file mode 100644 index 0000000000..04be5971bb --- /dev/null +++ b/src/main/kotlin/li/cli/oc/items/CPU.kt @@ -0,0 +1,9 @@ +package li.cli.oc.items + +import li.cli.oc.OpenComputers +import net.minecraft.item.Item + +class CPU(tier: Int) : Item(Settings().group(OpenComputers.ITEM_GROUP)) { + + +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/render/block/Screen.kt b/src/main/kotlin/li/cli/oc/render/block/Screen.kt new file mode 100644 index 0000000000..e20d344f7d --- /dev/null +++ b/src/main/kotlin/li/cli/oc/render/block/Screen.kt @@ -0,0 +1,163 @@ +package li.cli.oc.render.block + +import li.cli.oc.OpenComputers +import li.cli.oc.blockentity.Screen +import li.cli.oc.blocks.commons.BakedModelConfig +import li.cli.oc.blocks.commons.States +import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext +import net.minecraft.block.BlockState +import net.minecraft.client.MinecraftClient +import net.minecraft.client.texture.Sprite +import net.minecraft.client.texture.SpriteAtlasTexture +import net.minecraft.client.util.SpriteIdentifier +import net.minecraft.client.util.math.Vector4f + +import net.minecraft.item.ItemStack +import net.minecraft.util.Identifier +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import net.minecraft.world.BlockRenderView +import java.util.* +import java.util.function.Supplier + + +object Flags { + const val UP = 1 shl 0 + const val DOWN = 1 shl 1 + const val LEFT = 1 shl 2 + const val RIGHT = 1 shl 3 + + fun from(up: Boolean, down: Boolean, left: Boolean, right: Boolean): Int { + return (if (up) UP else 0) or (if (down) DOWN else 0) or (if (left) LEFT else 0) or if (right) RIGHT else 0 + } +} +class ScreenModel : BakedModelConfig() { + + override val spriteIds = arrayOf( + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/b")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bbl")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bbm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bbr")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bhb")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bhm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bht")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bml")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bmm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bmr")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/btl")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/btm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/btr")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bvb")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bvm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/bvt")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/f")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fbl")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fbm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fbr")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fhb")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fhm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fht")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fml")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fmm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fmr")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/ftl")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/ftm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/ftr")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fvb")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fvm")), + SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier(OpenComputers.modId, "block/screen/fvt")) + ) + override val sprites: Array = arrayOfNulls(spriteIds.size) + + private fun getFBTexture(data: Int?, isFront: Boolean): Sprite? { + return sprites[when(data) { + Flags.RIGHT or Flags.UP -> 1 + Flags.LEFT or Flags.RIGHT or Flags.UP -> 2 + Flags.LEFT or Flags.UP -> 3 + Flags.LEFT -> 4 + Flags.LEFT or Flags.RIGHT -> 5 + Flags.RIGHT -> 6 + Flags.RIGHT or Flags.UP or Flags.DOWN -> 7 + Flags.LEFT or Flags.RIGHT or Flags.UP or Flags.DOWN -> 8 + Flags.LEFT or Flags.UP or Flags.DOWN -> 9 + Flags.RIGHT or Flags.DOWN -> 10 + Flags.LEFT or Flags.RIGHT or Flags.DOWN -> 11 + Flags.LEFT or Flags.DOWN -> 12 + Flags.UP -> 13 + Flags.UP or Flags.DOWN -> 14 + Flags.DOWN -> 15 + else -> 0 + } + (if (isFront) 16 else 0)] + } + + private fun getSideTexture(data: Int?): Sprite? { + return sprites[when(data) { + Flags.LEFT or Flags.RIGHT, Flags.LEFT or Flags.RIGHT or Flags.DOWN, Flags.LEFT or Flags.RIGHT or Flags.UP -> 5 + Flags.RIGHT,Flags.RIGHT or Flags.DOWN,Flags.RIGHT or Flags.UP -> 4 + Flags.LEFT,Flags.LEFT or Flags.DOWN,Flags.LEFT or Flags.UP -> 6 + else -> 0 + }] + } + + override fun emitBlockQuads( + blockRenderView: BlockRenderView?, + blockState: BlockState?, + blockPos: BlockPos?, + supplier: Supplier?, + renderContext: RenderContext? + ) { + val emitter = renderContext?.emitter!! + val rotation = blockState?.get(States.Yaw)!! + val world = MinecraftClient.getInstance().world!! + val entity = world.getBlockEntity(blockPos)!! as Screen + val color = entity.getColor() + val defaultVector = Vector4f(0.0f, 0.0f, 1.0f, 1.0f) + when(blockState.get(States.Pitch)) { + Direction.UP -> { + val override = when(rotation) { + Direction.EAST -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_90 or MutableQuadView.BAKE_FLIP_U + Direction.WEST -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_90 or MutableQuadView.BAKE_FLIP_V + Direction.SOUTH -> MutableQuadView.BAKE_LOCK_UV + Direction.NORTH -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_180 + else -> MutableQuadView.BAKE_LOCK_UV + } + val override2 = when(rotation) { + Direction.EAST -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_90 + Direction.WEST -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_270 or MutableQuadView.BAKE_FLIP_V + Direction.SOUTH -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_FLIP_V + Direction.NORTH -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_180 or MutableQuadView.BAKE_FLIP_V + else -> MutableQuadView.BAKE_LOCK_UV + } + renderSprite(emitter, Direction.SOUTH, sprites[0], defaultVector, MutableQuadView.BAKE_LOCK_UV, color) +// renderSprite(emitter, Direction.NORTH, sprites[0], defaultVector, MutableQuadView.BAKE_LOCK_UV, color) + renderSprite(emitter, Direction.WEST, sprites[0], defaultVector, MutableQuadView.BAKE_LOCK_UV, color) + renderSprite(emitter, Direction.EAST, sprites[0], defaultVector, MutableQuadView.BAKE_LOCK_UV, color) + renderSprite(emitter, Direction.DOWN, getFBTexture(entity.connectedAt, false), defaultVector, override2, color) + + renderSprite(emitter, Direction.UP, getFBTexture(entity.connectedAt, true), 0.0f, 0.0f,1.0f,1.0f,0.0f, override, color) + } + Direction.NORTH -> { + val override = when(rotation) { + Direction.EAST -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_90 or MutableQuadView.BAKE_FLIP_V + Direction.WEST -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_270 + Direction.SOUTH -> MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_ROTATE_180 + Direction.NORTH -> MutableQuadView.BAKE_LOCK_UV + else -> MutableQuadView.BAKE_LOCK_UV + } + renderSprite(emitter, Direction.UP, getSideTexture(entity.connectedAt), defaultVector, override, color) + renderSprite(emitter, Direction.DOWN, getSideTexture(entity.connectedAt), defaultVector, override or if(rotation == Direction.WEST || rotation == Direction.EAST) MutableQuadView.BAKE_FLIP_U else 0, color) + renderSprite(emitter, rotation.rotateYClockwise(), sprites[0], defaultVector, MutableQuadView.BAKE_LOCK_UV, color) + renderSprite(emitter, rotation.rotateYCounterclockwise(), sprites[0], defaultVector, MutableQuadView.BAKE_LOCK_UV, color) + + renderSprite(emitter, rotation.opposite, getFBTexture(entity.connectedAt, false), 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, MutableQuadView.BAKE_LOCK_UV or MutableQuadView.BAKE_FLIP_U, color) + renderSprite(emitter, rotation, getFBTexture(entity.connectedAt, true), 0.0f, 0.0f,1.0f,1.0f,0.0f,MutableQuadView.BAKE_LOCK_UV, color) + } + Direction.DOWN -> { + renderSprite(emitter, Direction.DOWN, getFBTexture(entity.connectedAt, true), 0.0f, 0.0f,1.0f,1.0f,0.0f,MutableQuadView.BAKE_LOCK_UV, color) + } + else -> renderSprite(emitter, Direction.UP, sprites[2], 0.0f, 0.0f,1.0f,1.0f,0.0f) + } + } + override fun emitItemQuads(p0: ItemStack?, p1: Supplier?, p2: RenderContext?) { } +} \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/tileentity/Screen.kt b/src/main/kotlin/li/cli/oc/tileentity/Screen.kt deleted file mode 100644 index 7ba1d08a19..0000000000 --- a/src/main/kotlin/li/cli/oc/tileentity/Screen.kt +++ /dev/null @@ -1,18 +0,0 @@ -package li.cli.oc.tileentity - -import li.cli.oc.Components -import net.minecraft.block.entity.BlockEntity -import net.minecraft.block.entity.BlockEntityType - -private fun getEntityFromTier(Tier: Int): BlockEntityType { - return when(Tier) { - 1 -> Components.BlockEntities.ScreenOne.entityType - 2 -> Components.BlockEntities.ScreenTwo.entityType - 3 -> Components.BlockEntities.ScreenThree.entityType - else -> null!! - } -} - -class Screen(Tier: Int): BlockEntity(getEntityFromTier(Tier)) { - -} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index a3cabe5b4b..ee7120f49c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -35,7 +35,7 @@ "fabric": "*", "minecraft": "1.16.x" }, - "requires": { + "depends": { "fabric-language-kotlin": ">=1.4.0" }, "suggests": { From 3f24d2027b8f8ed6a49c4bc037a3fb65fb65d587 Mon Sep 17 00:00:00 2001 From: Ross Schulman Date: Mon, 21 Dec 2020 15:05:02 -0500 Subject: [PATCH 2/7] Revert changes to `Case` constructor in `Case.kt` and `Case` creation in `Components.kt` --- src/main/kotlin/li/cli/oc/Components.kt | 12 ++++++------ src/main/kotlin/li/cli/oc/blocks/Case.kt | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/li/cli/oc/Components.kt b/src/main/kotlin/li/cli/oc/Components.kt index 85479593dc..b728f1cefe 100644 --- a/src/main/kotlin/li/cli/oc/Components.kt +++ b/src/main/kotlin/li/cli/oc/Components.kt @@ -39,10 +39,10 @@ object Components { Cable("cable", Cable()), Capacitor("capacitor", Capacitor()), CarpatedCapacitor("carpetedcapacitor", CarpetedCapacitor()), - CaseOne("case1", Case(1, FabricBlockSettings.of(Material.METAL).nonOpaque())), - CaseTwo("case2", Case(2, FabricBlockSettings.of(Material.METAL).nonOpaque())), - CaseThree("case3", Case(3, FabricBlockSettings.of(Material.METAL).nonOpaque())), - CaseCreative("casecreative", Case(4, FabricBlockSettings.of(Material.METAL).nonOpaque())), + CaseOne("case1", Case(1)), + CaseTwo("case2", Case(2)), + CaseThree("case3", Case(3)), + CaseCreative("casecreative", Case(4)), Charger("charger", Charger()), Disassembler("disassembler", Disassembler()), DiskDrive("diskdrive", DiskDrive()), @@ -184,7 +184,7 @@ object Components { fun registerComponents() { caseEntityType = Registry.register(Registry.BLOCK_ENTITY_TYPE, Identifier(OpenComputers.modId, "case"), - BlockEntityType.Builder.create({ CaseEntity() }, Case(4, FabricBlockSettings.of(Material.METAL).nonOpaque())).build(null)) + BlockEntityType.Builder.create({ CaseEntity() }, Case(4)).build(null)) BlockEntities.values().iterator().forEach { x -> Registry.register(Registry.BLOCK_ENTITY_TYPE, Identifier(OpenComputers.modId, x.id), x.entityType) @@ -199,7 +199,7 @@ object Components { } } - val CASE1 = Case(1, FabricBlockSettings.of(Material.METAL).nonOpaque(), ) + val CASE1 = Case(1) val CASE_SCREEN_HANDLER: ScreenHandlerType = ScreenHandlerRegistry.registerSimple(Identifier(OpenComputers.modId, "case1"), ::CaseScreenHandler) } diff --git a/src/main/kotlin/li/cli/oc/blocks/Case.kt b/src/main/kotlin/li/cli/oc/blocks/Case.kt index e3865d41da..8ee452df0a 100644 --- a/src/main/kotlin/li/cli/oc/blocks/Case.kt +++ b/src/main/kotlin/li/cli/oc/blocks/Case.kt @@ -36,7 +36,7 @@ class CaseEntity : RedstoneAwareEntity(Components.caseEntityType), NamedScreenHa } } -class Case(var Tear: Int, settings: Settings) : TecBlock(settings) { +class Case(var Tear: Int) : TecBlock(FabricBlockSettings.of(Material.METAL).nonOpaque()) { override fun getColor(): Int { From 346d7c14a4a979f4940471cfdfbb736147237c27 Mon Sep 17 00:00:00 2001 From: Ross Schulman Date: Mon, 21 Dec 2020 15:40:22 -0500 Subject: [PATCH 3/7] Propagate case tier into Case BlockEntity and ScreenHandler --- src/main/kotlin/li/cli/oc/blocks/Case.kt | 10 +++++----- .../li/cli/oc/client/gui/blocks/CaseScreenHandler.kt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/li/cli/oc/blocks/Case.kt b/src/main/kotlin/li/cli/oc/blocks/Case.kt index 8ee452df0a..d2ad3ce245 100644 --- a/src/main/kotlin/li/cli/oc/blocks/Case.kt +++ b/src/main/kotlin/li/cli/oc/blocks/Case.kt @@ -25,10 +25,10 @@ import net.minecraft.util.math.Direction import net.minecraft.world.BlockView; import net.minecraft.world.World -class CaseEntity : RedstoneAwareEntity(Components.caseEntityType), NamedScreenHandlerFactory { +class CaseEntity(val tier: Int) : RedstoneAwareEntity(Components.caseEntityType), NamedScreenHandlerFactory { override fun createMenu(syncId: Int, inv: PlayerInventory, player: PlayerEntity): ScreenHandler { - return CaseScreenHandler(syncId, inv) + return CaseScreenHandler(syncId, inv, tier) } override fun getDisplayName(): Text { @@ -36,11 +36,11 @@ class CaseEntity : RedstoneAwareEntity(Components.caseEntityType), NamedScreenHa } } -class Case(var Tear: Int) : TecBlock(FabricBlockSettings.of(Material.METAL).nonOpaque()) { +class Case(var tier: Int) : TecBlock(FabricBlockSettings.of(Material.METAL).nonOpaque()) { override fun getColor(): Int { - return Color.getTearColors(Tear - 1); + return Color.getTearColors(tier - 1); } val facing = HorizontalFacingBlock.FACING; @@ -61,7 +61,7 @@ class Case(var Tear: Int) : TecBlock(FabricBlockSettings.of(Material.METAL).nonO } override fun createBlockEntity(world: BlockView?): BlockEntity? { - return CaseEntity(); + return CaseEntity(tier); } override fun getRenderType(state: BlockState?): BlockRenderType { diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt index 9f717b15cc..3974379cd4 100644 --- a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt @@ -8,7 +8,7 @@ import net.minecraft.inventory.SimpleInventory import net.minecraft.screen.ScreenHandler import net.minecraft.screen.slot.Slot -class CaseScreenHandler(syncId: Int, playerInventory: PlayerInventory) : ScreenHandler(Components.CASE_SCREEN_HANDLER, syncId) { +class CaseScreenHandler(syncId: Int, playerInventory: PlayerInventory, val tier: Int) : ScreenHandler(Components.CASE_SCREEN_HANDLER, syncId) { private val inventory = SimpleInventory(10) override fun canUse(player: PlayerEntity?): Boolean { From 49f479ba0557d110e6b5abd920f926d8f82c4937 Mon Sep 17 00:00:00 2001 From: Ross Schulman Date: Thu, 24 Dec 2020 13:27:49 -0500 Subject: [PATCH 4/7] Add new texture for slots Slots are not working properly yet because the `CaseScreenHandler` is seemingly created twice per GUI opening. Once from `CaseEntity` and once from its registration in`Components.kt`. The latter is generic across Case tiers, and so right now passes in 0 for the tier, which causes an array index out of bounds error. --- src/main/kotlin/li/cli/oc/Components.kt | 6 ++-- .../li/cli/oc/client/gui/blocks/CaseScreen.kt | 28 ++++++++++++++-- .../oc/client/gui/blocks/CaseScreenHandler.kt | 32 +++++++++---------- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/li/cli/oc/Components.kt b/src/main/kotlin/li/cli/oc/Components.kt index b728f1cefe..4dbaadc0c7 100644 --- a/src/main/kotlin/li/cli/oc/Components.kt +++ b/src/main/kotlin/li/cli/oc/Components.kt @@ -184,7 +184,7 @@ object Components { fun registerComponents() { caseEntityType = Registry.register(Registry.BLOCK_ENTITY_TYPE, Identifier(OpenComputers.modId, "case"), - BlockEntityType.Builder.create({ CaseEntity() }, Case(4)).build(null)) + BlockEntityType.Builder.create({ CaseEntity(4) }, Case(4)).build(null)) BlockEntities.values().iterator().forEach { x -> Registry.register(Registry.BLOCK_ENTITY_TYPE, Identifier(OpenComputers.modId, x.id), x.entityType) @@ -200,6 +200,8 @@ object Components { } val CASE1 = Case(1) - val CASE_SCREEN_HANDLER: ScreenHandlerType = ScreenHandlerRegistry.registerSimple(Identifier(OpenComputers.modId, "case1"), ::CaseScreenHandler) + val CASE_SCREEN_HANDLER: ScreenHandlerType = ScreenHandlerRegistry.registerSimple(Identifier(OpenComputers.modId)) { syncId, inventory -> + CaseScreenHandler(syncId, inventory, 0) + } } diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt index f4ae19d38c..f3591c2892 100644 --- a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt @@ -10,7 +10,11 @@ import net.minecraft.screen.ScreenHandler import net.minecraft.text.Text import net.minecraft.util.Identifier -class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Text?) : HandledScreen(handler, inventory, title) { +class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Text?) : HandledScreen( + handler, + inventory, + title +) { override fun drawBackground(matrices: MatrixStack?, delta: Float, mouseX: Int, mouseY: Int) { RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f) @@ -22,6 +26,15 @@ class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Te client!!.textureManager.bindTexture(COMP_TEXTURE) drawTexture(matrices, x, y + 1, 0, 0, 256, 256) + + client!!.textureManager.bindTexture(SLOT_TEXTURE) + val tier = (handler as CaseScreenHandler).tier + + var slotMatrix = MatrixStack() + slotMatrix.push() + slotMatrix.translate(0.0, 0.0, 5.0) + + drawTexture(slotMatrix, x + 42, y + 34, 0, 0, 18, 18) } @@ -37,7 +50,18 @@ class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Te val y = (height - backgroundHeight) / 2 // Center the title titleX = 7 - val powerButton = TexturedButtonWidget(x + (backgroundWidth / 2) - 18 , y + 34, 18, 18, 0, 0, 0, BUTTON_TEXTURE, 36, 36) { button -> + val powerButton = TexturedButtonWidget( + x + (backgroundWidth / 2) - 18, + y + 34, + 18, + 18, + 0, + 0, + 0, + BUTTON_TEXTURE, + 36, + 36 + ) { button -> TODO( "Computer start/stop here" ) diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt index 3974379cd4..7d1065518f 100644 --- a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt @@ -16,21 +16,21 @@ class CaseScreenHandler(syncId: Int, playerInventory: PlayerInventory, val tier: } init { - // BIOS Slot to the left of the power button - addSlot(Slot(inventory, 0, 20, 20)) - - // Two Expansion Slot Cards to the left of the component grid - addSlot(Slot(inventory, 1, 80, 10)) - addSlot(Slot(inventory, 2, 80, 30)) - - // One CPU Slot in the center top of the component grid - addSlot(Slot(inventory, 3, 100, 10)) - - // Two RAM Slots in the direct middle and bottom middle of the component grid - addSlot(Slot(inventory, 4, 100, 30)) - addSlot(Slot(inventory, 5, 100, 50)) - - // One HDD Slot in the top right of the component grid - addSlot(Slot(inventory, 6, 120, 10)) + addSlot(Slot(inventory, 0, 43, 35)) // EEPROM Slot + if (tier == 1) { + // Two Expansion Slot Cards to the left of the component grid + addSlot(Slot(inventory, 1, 80, 10)) + addSlot(Slot(inventory, 2, 80, 30)) + + // One CPU Slot in the center top of the component grid + addSlot(Slot(inventory, 3, 100, 10)) + + // Two RAM Slots in the direct middle and bottom middle of the component grid + addSlot(Slot(inventory, 4, 100, 30)) + addSlot(Slot(inventory, 5, 100, 50)) + + // One HDD Slot in the top right of the component grid + addSlot(Slot(inventory, 6, 120, 10)) + } } } \ No newline at end of file From 10c0929de29f16568c086bdf17584ed7508a8c65 Mon Sep 17 00:00:00 2001 From: Ross Schulman Date: Mon, 28 Dec 2020 11:23:23 -0500 Subject: [PATCH 5/7] Change Case into an ExtendedScreenHandler, trying to get correct case tier to affect slot layout --- src/main/kotlin/li/cli/oc/Components.kt | 5 +---- src/main/kotlin/li/cli/oc/blockentity/Case.kt | 10 +++++++-- .../li/cli/oc/client/gui/blocks/CaseScreen.kt | 2 -- .../oc/client/gui/blocks/CaseScreenHandler.kt | 21 +++++++++++++------ 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/li/cli/oc/Components.kt b/src/main/kotlin/li/cli/oc/Components.kt index 6b3d058344..60bc5601d3 100644 --- a/src/main/kotlin/li/cli/oc/Components.kt +++ b/src/main/kotlin/li/cli/oc/Components.kt @@ -184,8 +184,5 @@ object Components { } val CASE1 = Case(1) - val CASE_SCREEN_HANDLER: ScreenHandlerType = ScreenHandlerRegistry.registerSimple(Identifier(OpenComputers.modId)) { syncId, inventory -> - CaseScreenHandler(syncId, inventory, 0) - } - + val CASE_SCREEN_HANDLER: ScreenHandlerType = ScreenHandlerRegistry.registerExtended(Identifier(OpenComputers.modId), ::CaseScreenHandler) } diff --git a/src/main/kotlin/li/cli/oc/blockentity/Case.kt b/src/main/kotlin/li/cli/oc/blockentity/Case.kt index 8808a70b68..2c877f81a3 100644 --- a/src/main/kotlin/li/cli/oc/blockentity/Case.kt +++ b/src/main/kotlin/li/cli/oc/blockentity/Case.kt @@ -3,13 +3,15 @@ package li.cli.oc.blockentity import li.cli.oc.blocks.commons.RedstoneAwareEntity import li.cli.oc.client.gui.blocks.CaseScreenHandler import li.cli.oc.components.BlockEntitiesComponent +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerInventory -import net.minecraft.screen.NamedScreenHandlerFactory +import net.minecraft.network.PacketByteBuf import net.minecraft.screen.ScreenHandler +import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.text.Text -class CaseEntity(val Tier: Int) : RedstoneAwareEntity(BlockEntitiesComponent.Case), NamedScreenHandlerFactory { +class CaseEntity(val Tier: Int) : RedstoneAwareEntity(BlockEntitiesComponent.Case), ExtendedScreenHandlerFactory { override fun createMenu(syncId: Int, inv: PlayerInventory, player: PlayerEntity): ScreenHandler { return CaseScreenHandler(syncId, inv, Tier) } @@ -17,4 +19,8 @@ class CaseEntity(val Tier: Int) : RedstoneAwareEntity(BlockEntitiesComponent.Cas override fun getDisplayName(): Text { return Text.of("Computer") } + + override fun writeScreenOpeningData(playerEntity: ServerPlayerEntity?, buf: PacketByteBuf?) { + buf?.writeInt(Tier) + } } \ No newline at end of file diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt index f3591c2892..0e158c9f6e 100644 --- a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt @@ -67,8 +67,6 @@ class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Te ) } addButton(powerButton) - - } companion object { diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt index 7d1065518f..dd34f7488f 100644 --- a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt @@ -5,19 +5,24 @@ import li.cli.oc.client.gui.blocks.slots.* import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerInventory import net.minecraft.inventory.SimpleInventory +import net.minecraft.network.PacketByteBuf import net.minecraft.screen.ScreenHandler import net.minecraft.screen.slot.Slot -class CaseScreenHandler(syncId: Int, playerInventory: PlayerInventory, val tier: Int) : ScreenHandler(Components.CASE_SCREEN_HANDLER, syncId) { +class CaseScreenHandler : ScreenHandler { private val inventory = SimpleInventory(10) + var tier = 0 - override fun canUse(player: PlayerEntity?): Boolean { - return inventory.canPlayerUse(player) + constructor(syncId: Int, playerInventory: PlayerInventory, buf: PacketByteBuf) : this(syncId, playerInventory, null) { + this.tier = buf.readInt() } - init { + constructor(syncId: Int, playerInventory: PlayerInventory, _tier: Int?) : super(Components.CASE_SCREEN_HANDLER, syncId) { + if (_tier != null) { + this.tier = _tier + } addSlot(Slot(inventory, 0, 43, 35)) // EEPROM Slot - if (tier == 1) { + if (this.tier == 1) { // Two Expansion Slot Cards to the left of the component grid addSlot(Slot(inventory, 1, 80, 10)) addSlot(Slot(inventory, 2, 80, 30)) @@ -33,4 +38,8 @@ class CaseScreenHandler(syncId: Int, playerInventory: PlayerInventory, val tier: addSlot(Slot(inventory, 6, 120, 10)) } } -} \ No newline at end of file + + override fun canUse(player: PlayerEntity?): Boolean { + return inventory.canPlayerUse(player) + } +} From 19c42527e15fd821ed9a815e68a8a2959b890150 Mon Sep 17 00:00:00 2001 From: Ross Schulman Date: Wed, 30 Dec 2020 12:25:06 -0500 Subject: [PATCH 6/7] Add toTag and fromTag for Case entity to store and recover entity tier --- src/main/kotlin/li/cli/oc/blockentity/Case.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/li/cli/oc/blockentity/Case.kt b/src/main/kotlin/li/cli/oc/blockentity/Case.kt index 2c877f81a3..b6b9fe4981 100644 --- a/src/main/kotlin/li/cli/oc/blockentity/Case.kt +++ b/src/main/kotlin/li/cli/oc/blockentity/Case.kt @@ -4,14 +4,20 @@ import li.cli.oc.blocks.commons.RedstoneAwareEntity import li.cli.oc.client.gui.blocks.CaseScreenHandler import li.cli.oc.components.BlockEntitiesComponent import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory +import net.minecraft.block.BlockState import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerInventory +import net.minecraft.nbt.CompoundTag import net.minecraft.network.PacketByteBuf import net.minecraft.screen.ScreenHandler import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.text.Text -class CaseEntity(val Tier: Int) : RedstoneAwareEntity(BlockEntitiesComponent.Case), ExtendedScreenHandlerFactory { +class CaseEntity(var Tier: Int) : RedstoneAwareEntity(BlockEntitiesComponent.Case), ExtendedScreenHandlerFactory { + init { + markDirty() + } + override fun createMenu(syncId: Int, inv: PlayerInventory, player: PlayerEntity): ScreenHandler { return CaseScreenHandler(syncId, inv, Tier) } @@ -23,4 +29,15 @@ class CaseEntity(val Tier: Int) : RedstoneAwareEntity(BlockEntitiesComponent.Cas override fun writeScreenOpeningData(playerEntity: ServerPlayerEntity?, buf: PacketByteBuf?) { buf?.writeInt(Tier) } + + override fun toTag(tag: CompoundTag): CompoundTag { + super.toTag(tag) + tag.putInt("tier", Tier) + return tag + } + + override fun fromTag(state: BlockState?, tag: CompoundTag?) { + super.fromTag(state, tag) + Tier = tag?.getInt("tier")!! + } } \ No newline at end of file From 5f7e00057e053151967990b5a5db63184a2d22c8 Mon Sep 17 00:00:00 2001 From: Ross Schulman Date: Wed, 30 Dec 2020 12:26:05 -0500 Subject: [PATCH 7/7] Add and align slots for tier 1 and 2, and slot textures for tier 1 --- .../li/cli/oc/client/gui/blocks/CaseScreen.kt | 26 ++++++++++++--- .../oc/client/gui/blocks/CaseScreenHandler.kt | 33 ++++++++++++++----- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt index 0e158c9f6e..6f47651cc6 100644 --- a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreen.kt @@ -30,11 +30,9 @@ class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Te client!!.textureManager.bindTexture(SLOT_TEXTURE) val tier = (handler as CaseScreenHandler).tier - var slotMatrix = MatrixStack() - slotMatrix.push() - slotMatrix.translate(0.0, 0.0, 5.0) + drawTexture(matrices, x + 42, y + 34, 0, 0, 18, 18) - drawTexture(slotMatrix, x + 42, y + 34, 0, 0, 18, 18) + drawInvSlots(tier!!, x, y) // Tier should almost certainly be set by the time we are drawing the background } @@ -69,6 +67,26 @@ class CaseScreen(handler: ScreenHandler?, inventory: PlayerInventory?, title: Te addButton(powerButton) } + private fun drawInvSlots(tier: Int, x: Int, y: Int) { + var invSlotMatrix = MatrixStack() + + client!!.textureManager.bindTexture(SLOT_TEXTURE) + + val xOffset = 93 + val yOffset = 12 + + //drawTexture(invSlotMatrix, x + xOffset, y + yOffset, 0, 0, 18, 18) + + drawTexture(invSlotMatrix, x + xOffset + 3, y + yOffset + 3, 0, 0, 18, 18) + drawTexture(invSlotMatrix, x + xOffset + 3, y + yOffset + 21, 0, 0, 18, 18) + + drawTexture(invSlotMatrix, x + xOffset + 3 + 18 + 5, y + yOffset + 3, 0, 0, 18, 18) + drawTexture(invSlotMatrix, x + xOffset + 3 + 18 + 5, y + yOffset + 21, 0, 0, 18, 18) + drawTexture(invSlotMatrix, x + xOffset + 3 + 18 + 5, y + yOffset + 39, 0, 0, 18, 18) + + drawTexture(invSlotMatrix, x + xOffset + 3 + 36 + 10, y + yOffset + 3, 0, 0, 18, 18) + } + companion object { private val TEXTURE = Identifier(OpenComputers.modId, "textures/gui/background.png") private val COMP_TEXTURE = Identifier(OpenComputers.modId, "textures/gui/computer.png") diff --git a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt index dd34f7488f..064385bd9a 100644 --- a/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt +++ b/src/main/kotlin/li/cli/oc/client/gui/blocks/CaseScreenHandler.kt @@ -11,10 +11,9 @@ import net.minecraft.screen.slot.Slot class CaseScreenHandler : ScreenHandler { private val inventory = SimpleInventory(10) - var tier = 0 + var tier: Int? = null - constructor(syncId: Int, playerInventory: PlayerInventory, buf: PacketByteBuf) : this(syncId, playerInventory, null) { - this.tier = buf.readInt() + constructor(syncId: Int, playerInventory: PlayerInventory, buf: PacketByteBuf) : this(syncId, playerInventory, buf.readInt()) { } constructor(syncId: Int, playerInventory: PlayerInventory, _tier: Int?) : super(Components.CASE_SCREEN_HANDLER, syncId) { @@ -24,18 +23,34 @@ class CaseScreenHandler : ScreenHandler { addSlot(Slot(inventory, 0, 43, 35)) // EEPROM Slot if (this.tier == 1) { // Two Expansion Slot Cards to the left of the component grid - addSlot(Slot(inventory, 1, 80, 10)) - addSlot(Slot(inventory, 2, 80, 30)) + addSlot(Slot(inventory, 1, 97, 16)) + addSlot(Slot(inventory, 2, 97, 34)) // One CPU Slot in the center top of the component grid - addSlot(Slot(inventory, 3, 100, 10)) + addSlot(Slot(inventory, 3, 120, 16)) // Two RAM Slots in the direct middle and bottom middle of the component grid - addSlot(Slot(inventory, 4, 100, 30)) - addSlot(Slot(inventory, 5, 100, 50)) + addSlot(Slot(inventory, 4, 120, 34)) + addSlot(Slot(inventory, 5, 120, 52)) // One HDD Slot in the top right of the component grid - addSlot(Slot(inventory, 6, 120, 10)) + addSlot(Slot(inventory, 6, 143, 16)) + } + if (this.tier == 2) { + // Two Expansion Slot Cards to the left of the component grid + addSlot(Slot(inventory, 1, 97, 16)) + addSlot(Slot(inventory, 2, 97, 34)) + + // One CPU Slot in the center top of the component grid + addSlot(Slot(inventory, 3, 120, 16)) + + // Two RAM Slots in the direct middle and bottom middle of the component grid + addSlot(Slot(inventory, 4, 120, 34)) + addSlot(Slot(inventory, 5, 120, 52)) + + // Two HDD Slots in the top right and middle right of the component grid + addSlot(Slot(inventory, 6, 143, 16)) + addSlot(Slot(inventory, 7, 143, 34)) } }