Merge branch 'master-MC1.7.10' of github.com:MightyPirates/OpenComputers into master-MC1.8

Conflicts:
	src/main/scala/li/cil/oc/client/Textures.scala
	src/main/scala/li/cil/oc/client/gui/Assembler.scala
	src/main/scala/li/cil/oc/client/gui/Database.scala
	src/main/scala/li/cil/oc/client/gui/Manual.scala
	src/main/scala/li/cil/oc/client/gui/Server.scala
	src/main/scala/li/cil/oc/client/gui/ServerRack.scala
	src/main/scala/li/cil/oc/common/item/FloppyDisk.scala
	src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala
	src/main/scala/li/cil/oc/server/machine/Machine.scala
This commit is contained in:
Florian Nücke 2015-08-02 21:22:46 +02:00
commit 3d663fee35
42 changed files with 685 additions and 181 deletions

View File

@ -205,9 +205,7 @@ opencomputers {
allowBytecode: false allowBytecode: false
# Whether to make the Lua 5.3 architecture available. If enabled, you # Whether to make the Lua 5.3 architecture available. If enabled, you
# can reconfigure any CPU to use the Lua 5.3 architecture. This is # can reconfigure any CPU to use the Lua 5.3 architecture.
# not enabled by default for the time being, because it needs some
# more stability testing.
enableLua53: true enableLua53: true
# The sizes of the six levels of RAM, in kilobytes. This list must # The sizes of the six levels of RAM, in kilobytes. This list must
@ -853,6 +851,20 @@ opencomputers {
# runs on. As a side effect this pretty much determines the read # runs on. As a side effect this pretty much determines the read
# performance of file systems. # performance of file systems.
maxReadBuffer: 2048 maxReadBuffer: 2048
# Number of physical platters to pretend a disk has in unmanged mode. This
# controls seek times, in how it emulates sectors overlapping (thus sharing
# a common head position for access).
hddPlatterCounts: [ 2, 4, 6 ]
# When skipping more than this number of sectors in unmanaged mode, the
# pause specified in sectorSeekTime will be enforced. We use this instead
# of linear scaling for movement because those values would have to be
# really small, which is hard to conceptualize and configure.
sectorSeekThreshold: 128
# The time to pause when the head movement threshold is exceeded.
sectorSeekTime: 0.1
} }
# Internet settings, security related. # Internet settings, security related.

View File

@ -191,6 +191,9 @@ oc:gui.Chat.WarningPower=No supported power providing mod available. Computers,
oc:gui.Chat.WarningProjectRed=You are using a version of Project: Red that is incompatible with OpenComputers. Try updating your version of Project: Red. oc:gui.Chat.WarningProjectRed=You are using a version of Project: Red that is incompatible with OpenComputers. Try updating your version of Project: Red.
oc:gui.Chat.WarningRecipes=There were errors loading one or more recipes. Some items may be uncraftable. Please check your log file for more information. oc:gui.Chat.WarningRecipes=There were errors loading one or more recipes. Some items may be uncraftable. Please check your log file for more information.
oc:gui.Chat.WarningSimpleComponent=An addon (yours?) using the §aSimpleComponent§f interface did §esomething wrong§f. Component logic could not be injected. Please check your log file for more information. oc:gui.Chat.WarningSimpleComponent=An addon (yours?) using the §aSimpleComponent§f interface did §esomething wrong§f. Component logic could not be injected. Please check your log file for more information.
oc:gui.Drive.Managed=Managed
oc:gui.Drive.Unmanaged=Unmanaged
oc:gui.Drive.Warning=§lWarning§r: switching modes will result in a loss of all data currently stored on the disk!
oc:gui.Error.ComponentOverflow=Too many components connected to the computer. oc:gui.Error.ComponentOverflow=Too many components connected to the computer.
oc:gui.Error.InternalError=Internal error, please see the log file. This is probably a bug. oc:gui.Error.InternalError=Internal error, please see the log file. This is probably a bug.
oc:gui.Error.NoCPU=No CPU is installed in the computer. oc:gui.Error.NoCPU=No CPU is installed in the computer.
@ -272,6 +275,9 @@ oc:tooltip.Disassembler=Separates items into their original components. §lWarni
oc:tooltip.Disk=Primitive medium that can be used to build persistent storage devices. oc:tooltip.Disk=Primitive medium that can be used to build persistent storage devices.
oc:tooltip.DiskDrive.CC=ComputerCraft floppies are §asupported§7. oc:tooltip.DiskDrive.CC=ComputerCraft floppies are §asupported§7.
oc:tooltip.DiskDrive=Allows reading and writing floppies. Can be installed in robots to allow inserting floppies later on. oc:tooltip.DiskDrive=Allows reading and writing floppies. Can be installed in robots to allow inserting floppies later on.
oc:tooltip.DiskUsage=Disk usage: %s/%s Byte
oc:tooltip.DiskModeManaged=Mode: Managed
oc:tooltip.DiskModeUnmanaged=Mode: Unmanaged
oc:tooltip.Drone=Drones are light-weight, fast reconnaissance units with limited cargo space. oc:tooltip.Drone=Drones are light-weight, fast reconnaissance units with limited cargo space.
oc:tooltip.DroneCase=This casing is used to build Drones in the assembler. It has room for a small amount of components and provides endstone-powered levitation. oc:tooltip.DroneCase=This casing is used to build Drones in the assembler. It has room for a small amount of components and provides endstone-powered levitation.
oc:tooltip.EEPROM=Small, programmable storage that contains the BIOS computers use to boot. oc:tooltip.EEPROM=Small, programmable storage that contains the BIOS computers use to boot.

View File

@ -0,0 +1,90 @@
--[[ Backwards compat for Lua 5.3; only loaded in 5.3 because package.loaded is
prepopulated with the existing global bit32 in 5.2. ]]
local bit32 = {}
-------------------------------------------------------------------------------
local function fold(init, op, ...)
local result = init
local args = table.pack(...)
for i = 1, args.n do
result = op(result, args[i])
end
return result
end
local function trim(n)
return n & 0xFFFFFFFF
end
local function mask(w)
return ~(0xFFFFFFFF << w)
end
function bit32.arshift(x, disp)
return x // (2 ^ disp)
end
function bit32.band(...)
return fold(0xFFFFFFFF, function(a, b) return a & b end, ...)
end
function bit32.bnot(x)
return ~x
end
function bit32.bor(...)
return fold(0, function(a, b) return a | b end, ...)
end
function bit32.btest(...)
return bit32.band(...) ~= 0
end
function bit32.bxor(...)
return fold(0, function(a, b) return a ~ b end, ...)
end
local function fieldargs(f, w)
w = w or 1
assert(f >= 0, "field cannot be negative")
assert(w > 0, "width must be positive")
assert(f + w <= 32, "trying to access non-existent bits")
return f, w
end
function bit32.extract(n, field, width)
local f, w = fieldargs(field, width)
return (n >> f) & mask(w)
end
function bit32.replace(n, v, field, width)
local f, w = fieldargs(field, width)
local m = mask(w)
return (n & ~(m << f)) | ((v & m) << f)
end
function bit32.lrotate(x, disp)
if disp == 0 then return x
elseif disp < 0 then return bit32.rrotate(x, -disp)
else return trim((x << disp) | (x >> (32 - disp))) end
end
function bit32.lshift(x, disp)
return trim(x << disp)
end
function bit32.rrotate(x, disp)
if disp == 0 then return x
elseif disp < 0 then return bit32.lrotate(x, -disp)
else return trim((x >> disp) | (x << (32 - disp))) end
end
function bit32.rshift(x, disp)
return trim(x >> disp)
end
-------------------------------------------------------------------------------
return bit32

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

View File

@ -112,6 +112,14 @@ object Localization {
def Power = localizeImmediately("gui.Robot.Power") def Power = localizeImmediately("gui.Robot.Power")
} }
object Drive {
def Managed = localizeImmediately("gui.Drive.Managed")
def Unmanaged = localizeImmediately("gui.Drive.Unmanaged")
def Warning = localizeImmediately("gui.Drive.Warning")
}
object Raid { object Raid {
def Warning = localizeImmediately("gui.Raid.Warning") def Warning = localizeImmediately("gui.Raid.Warning")
} }
@ -151,6 +159,10 @@ object Localization {
} }
object Tooltip { object Tooltip {
def DiskUsage(used: Long, capacity: Long) = localizeImmediately("tooltip.DiskUsage", used.toString, capacity.toString)
def DiskMode(isUnmanaged: Boolean) = localizeImmediately(if (isUnmanaged) "tooltip.DiskModeUnmanaged" else "tooltip.DiskModeManaged")
def Materials = localizeImmediately("tooltip.Materials") def Materials = localizeImmediately("tooltip.Materials")
def Tier(tier: Int) = localizeImmediately("tooltip.Tier", tier.toString) def Tier(tier: Int) = localizeImmediately("tooltip.Tier", tier.toString)

View File

@ -248,10 +248,19 @@ class Settings(val config: Config) {
OpenComputers.log.warn("Bad number of HDD sizes, ignoring.") OpenComputers.log.warn("Bad number of HDD sizes, ignoring.")
Array(1024, 2048, 4096) Array(1024, 2048, 4096)
} }
val hddPlatterCounts = Array(config.getIntList("filesystem.hddPlatterCounts"): _*) match {
case Array(tier1, tier2, tier3) =>
Array(tier1: Int, tier2: Int, tier3: Int)
case _ =>
OpenComputers.log.warn("Bad number of HDD platter counts, ignoring.")
Array(2, 4, 6)
}
val floppySize = config.getInt("filesystem.floppySize") max 0 val floppySize = config.getInt("filesystem.floppySize") max 0
val tmpSize = config.getInt("filesystem.tmpSize") max 0 val tmpSize = config.getInt("filesystem.tmpSize") max 0
val maxHandles = config.getInt("filesystem.maxHandles") max 0 val maxHandles = config.getInt("filesystem.maxHandles") max 0
val maxReadBuffer = config.getInt("filesystem.maxReadBuffer") max 0 val maxReadBuffer = config.getInt("filesystem.maxReadBuffer") max 0
val sectorSeekThreshold = config.getInt("filesystem.sectorSeekThreshold")
val sectorSeekTime = config.getDouble("filesystem.sectorSeekTime")
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
// internet // internet

View File

@ -58,6 +58,8 @@ object GuiHandler extends CommonGuiHandler {
} }
case Some(GuiType.Category.Item) => case Some(GuiType.Category.Item) =>
Delegator.subItem(player.getCurrentEquippedItem) match { Delegator.subItem(player.getCurrentEquippedItem) match {
case Some(drive: item.traits.FileSystemLike) if id == GuiType.Drive.id =>
new gui.Drive(player.inventory, () => player.getCurrentEquippedItem)
case Some(database: item.UpgradeDatabase) if id == GuiType.Database.id => case Some(database: item.UpgradeDatabase) if id == GuiType.Database.id =>
new gui.Database(player.inventory, new DatabaseInventory { new gui.Database(player.inventory, new DatabaseInventory {
override def tier = database.tier override def tier = database.tier

View File

@ -26,6 +26,14 @@ object PacketSender {
pb.sendToServer() pb.sendToServer()
} }
def sendDriveMode(unmanaged: Boolean) {
val pb = new SimplePacketBuilder(PacketType.DriveMode)
pb.writeBoolean(unmanaged)
pb.sendToServer()
}
def sendDronePower(e: Drone, power: Boolean) { def sendDronePower(e: Drone, power: Boolean) {
val pb = new SimplePacketBuilder(PacketType.DronePower) val pb = new SimplePacketBuilder(PacketType.DronePower)

View File

@ -28,6 +28,7 @@ object Textures {
val Background = L("background") val Background = L("background")
val Bar = L("bar") val Bar = L("bar")
val Borders = L("borders") val Borders = L("borders")
val ButtonDriveMode = L("button_drive_mode")
val ButtonPower = L("button_power") val ButtonPower = L("button_power")
val ButtonRange = L("button_range") val ButtonRange = L("button_range")
val ButtonRun = L("button_run") val ButtonRun = L("button_run")
@ -39,6 +40,7 @@ object Textures {
val Database1 = L("database1") val Database1 = L("database1")
val Database2 = L("database2") val Database2 = L("database2")
val Disassembler = L("disassembler") val Disassembler = L("disassembler")
val Drive = L("drive")
val Drone = L("drone") val Drone = L("drone")
val KeyboardMissing = L("keyboard_missing") val KeyboardMissing = L("keyboard_missing")
val Manual = L("manual") val Manual = L("manual")

View File

@ -1,7 +1,5 @@
package li.cil.oc.client.gui package li.cil.oc.client.gui
import java.util
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.client.Textures import li.cil.oc.client.Textures
import li.cil.oc.client.gui.widget.ProgressBar import li.cil.oc.client.gui.widget.ProgressBar
@ -36,17 +34,13 @@ class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Asse
var info: Option[(Boolean, IChatComponent, Array[IChatComponent])] = None var info: Option[(Boolean, IChatComponent, Array[IChatComponent])] = None
private def assemblerContainer = inventorySlots.asInstanceOf[container.Assembler]
protected var runButton: ImageButton = _ protected var runButton: ImageButton = _
private val progress = addWidget(new ProgressBar(28, 92)) private val progress = addWidget(new ProgressBar(28, 92))
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T]) private def validate = AssemblerTemplates.select(inventoryContainer.getSlot(0).getStack).map(_.validate(inventoryContainer.otherInventory))
private def validate = AssemblerTemplates.select(assemblerContainer.getSlot(0).getStack).map(_.validate(assemblerContainer.otherInventory)) private def canBuild = !inventoryContainer.isAssembling && validate.exists(_._1)
private def canBuild = !assemblerContainer.isAssembling && validate.exists(_._1)
protected override def actionPerformed(button: GuiButton) { protected override def actionPerformed(button: GuiButton) {
if (button.id == 0 && canBuild) { if (button.id == 0 && canBuild) {
@ -62,14 +56,14 @@ class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Asse
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
RenderState.pushAttrib() RenderState.pushAttrib()
if (!assemblerContainer.isAssembling) { if (!inventoryContainer.isAssembling) {
val message = val message =
if (!assemblerContainer.getSlot(0).getHasStack) { if (!inventoryContainer.getSlot(0).getHasStack) {
Localization.Assembler.InsertTemplate Localization.Assembler.InsertTemplate
} }
else info match { else info match {
case Some((_, value, _)) if value != null => value.getUnformattedText case Some((_, value, _)) if value != null => value.getUnformattedText
case _ if assemblerContainer.getSlot(0).getHasStack => Localization.Assembler.CollectResult case _ if inventoryContainer.getSlot(0).getHasStack => Localization.Assembler.CollectResult
case _ => "" case _ => ""
} }
fontRendererObj.drawString(message, 30, 94, 0x404040) fontRendererObj.drawString(message, 30, 94, 0x404040)
@ -86,8 +80,8 @@ class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Asse
} }
else if (isPointInRegion(progress.x, progress.y, progress.width, progress.height, mouseX, mouseY)) { else if (isPointInRegion(progress.x, progress.y, progress.width, progress.height, mouseX, mouseY)) {
val tooltip = new java.util.ArrayList[String] val tooltip = new java.util.ArrayList[String]
val timeRemaining = formatTime(assemblerContainer.assemblyRemainingTime) val timeRemaining = formatTime(inventoryContainer.assemblyRemainingTime)
tooltip.add(Localization.Assembler.Progress(assemblerContainer.assemblyProgress, timeRemaining)) tooltip.add(Localization.Assembler.Progress(inventoryContainer.assemblyProgress, timeRemaining))
copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj) copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj)
} }
RenderState.popAttrib() RenderState.popAttrib()
@ -103,13 +97,11 @@ class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Asse
RenderState.color(1, 1, 1) // Required under Linux. RenderState.color(1, 1, 1) // Required under Linux.
Textures.bind(Textures.GUI.RobotAssembler) Textures.bind(Textures.GUI.RobotAssembler)
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize)
if (assemblerContainer.isAssembling) progress.level = assemblerContainer.assemblyProgress / 100.0 if (inventoryContainer.isAssembling) progress.level = inventoryContainer.assemblyProgress / 100.0
else progress.level = 0 else progress.level = 0
drawWidgets() drawWidgets()
drawInventorySlots() drawInventorySlots()
} }
override protected def drawDisabledSlot(slot: ComponentSlot) {} override protected def drawDisabledSlot(slot: ComponentSlot) {}
override def doesGuiPauseGame = false
} }

View File

@ -1,7 +1,5 @@
package li.cil.oc.client.gui package li.cil.oc.client.gui
import java.util
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.client.Textures import li.cil.oc.client.Textures
import li.cil.oc.client.{PacketSender => ClientPacketSender} import li.cil.oc.client.{PacketSender => ClientPacketSender}
@ -16,8 +14,6 @@ import scala.collection.convert.WrapAsJava._
class Case(playerInventory: InventoryPlayer, val computer: tileentity.Case) extends DynamicGuiContainer(new container.Case(playerInventory, computer)) { class Case(playerInventory: InventoryPlayer, val computer: tileentity.Case) extends DynamicGuiContainer(new container.Case(playerInventory, computer)) {
protected var powerButton: ImageButton = _ protected var powerButton: ImageButton = _
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
protected override def actionPerformed(button: GuiButton) { protected override def actionPerformed(button: GuiButton) {
if (button.id == 0) { if (button.id == 0) {
ClientPacketSender.sendComputerPower(computer, !computer.isRunning) ClientPacketSender.sendComputerPower(computer, !computer.isRunning)
@ -52,6 +48,4 @@ class Case(playerInventory: InventoryPlayer, val computer: tileentity.Case) exte
Textures.bind(Textures.GUI.Computer) Textures.bind(Textures.GUI.Computer)
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize)
} }
override def doesGuiPauseGame = false
} }

View File

@ -14,13 +14,17 @@ import scala.collection.convert.WrapAsScala._
// transformations that break things! Such fun. Many annoyed. And yes, this // transformations that break things! Such fun. Many annoyed. And yes, this
// is a common issue, have a look at EnderIO and Enchanting Plus. They have // is a common issue, have a look at EnderIO and Enchanting Plus. They have
// to work around this, too. // to work around this, too.
abstract class CustomGuiContainer(container: Container) extends GuiContainer(container) with WidgetContainer { abstract class CustomGuiContainer[C <: Container](val inventoryContainer: C) extends GuiContainer(inventoryContainer) with WidgetContainer {
override def windowX = guiLeft override def windowX = guiLeft
override def windowY = guiTop override def windowY = guiTop
override def windowZ = zLevel override def windowZ = zLevel
override def doesGuiPauseGame = false
protected def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
// Pretty much Scalaified copy-pasta from base-class. // Pretty much Scalaified copy-pasta from base-class.
override def drawHoveringText(text: util.List[_], x: Int, y: Int, font: FontRenderer): Unit = { override def drawHoveringText(text: util.List[_], x: Int, y: Int, font: FontRenderer): Unit = {
copiedDrawHoveringText(text, x, y, font) copiedDrawHoveringText(text, x, y, font)

View File

@ -6,11 +6,12 @@ import li.cil.oc.common.container
import li.cil.oc.common.inventory.DatabaseInventory import li.cil.oc.common.inventory.DatabaseInventory
import li.cil.oc.util.RenderState import li.cil.oc.util.RenderState
import net.minecraft.entity.player.InventoryPlayer import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.inventory.Slot
class Database(playerInventory: InventoryPlayer, val databaseInventory: DatabaseInventory) extends DynamicGuiContainer(new container.Database(playerInventory, databaseInventory)) { class Database(playerInventory: InventoryPlayer, val databaseInventory: DatabaseInventory) extends DynamicGuiContainer(new container.Database(playerInventory, databaseInventory)) with traits.LockedHotbar {
ySize = 256 ySize = 256
override def lockedStack = databaseInventory.container
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {} override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {}
override protected def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) { override protected def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) {
@ -28,14 +29,4 @@ class Database(playerInventory: InventoryPlayer, val databaseInventory: Database
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize)
} }
} }
override def doesGuiPauseGame = false
protected override def handleMouseClick(slot: Slot, slotNumber: Int, button: Int, shift: Int) {
if (slot == null || slot.getStack != databaseInventory.container) {
super.handleMouseClick(slot, slotNumber, button, shift)
}
}
protected override def checkHotbarKeys(slot: Int) = false
} }

View File

@ -9,8 +9,6 @@ import li.cil.oc.util.RenderState
import net.minecraft.entity.player.InventoryPlayer import net.minecraft.entity.player.InventoryPlayer
class Disassembler(playerInventory: InventoryPlayer, val disassembler: tileentity.Disassembler) extends DynamicGuiContainer(new container.Disassembler(playerInventory, disassembler)) { class Disassembler(playerInventory: InventoryPlayer, val disassembler: tileentity.Disassembler) extends DynamicGuiContainer(new container.Disassembler(playerInventory, disassembler)) {
private def disassemblerContainer = inventorySlots.asInstanceOf[container.Disassembler]
val progress = addWidget(new ProgressBar(18, 65)) val progress = addWidget(new ProgressBar(18, 65))
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
@ -23,7 +21,7 @@ class Disassembler(playerInventory: InventoryPlayer, val disassembler: tileentit
RenderState.color(1, 1, 1) RenderState.color(1, 1, 1)
Textures.bind(Textures.GUI.Disassembler) Textures.bind(Textures.GUI.Disassembler)
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize)
progress.level = disassemblerContainer.disassemblyProgress / 100.0 progress.level = inventoryContainer.disassemblyProgress / 100.0
drawWidgets() drawWidgets()
} }
} }

View File

@ -0,0 +1,47 @@
package li.cil.oc.client.gui
import li.cil.oc.Localization
import li.cil.oc.client.Textures
import li.cil.oc.client.{PacketSender => ClientPacketSender}
import li.cil.oc.common.item.data.DriveData
import net.minecraft.client.gui.GuiButton
import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.item.ItemStack
class Drive(playerInventory: InventoryPlayer, val driveStack: () => ItemStack) extends GuiScreen with traits.Window {
override val windowHeight = 85
override def backgroundImage = Textures.GUI.Drive
protected var managedButton: ImageButton = _
protected var unmanagedButton: ImageButton = _
protected override def actionPerformed(button: GuiButton) {
if (button.id == 0) {
ClientPacketSender.sendDriveMode(false)
}
if (button.id == 1) {
ClientPacketSender.sendDriveMode(true)
}
}
override def initGui(): Unit = {
super.initGui()
managedButton = new ImageButton(0, guiLeft + 11, guiTop + 11, 74, 18, Textures.GUI.ButtonDriveMode, text = Localization.Drive.Managed, textColor = 0x608060, canToggle = true)
unmanagedButton = new ImageButton(1, guiLeft + 91, guiTop + 11, 74, 18, Textures.GUI.ButtonDriveMode, text = Localization.Drive.Unmanaged, textColor = 0x608060, canToggle = true)
add(buttonList, managedButton)
add(buttonList, unmanagedButton)
}
override def updateScreen(): Unit = {
unmanagedButton.toggled = new DriveData(driveStack()).isUnmanaged
managedButton.toggled = !unmanagedButton.toggled
super.updateScreen()
}
override def drawScreen(mouseX: Int, mouseY: Int, dt: Float): Unit = {
super.drawScreen(mouseX, mouseY, dt)
fontRendererObj.drawSplitString(Localization.Drive.Warning, guiLeft + 7, guiTop + 37, xSize - 16, 0x404040)
}
}

View File

@ -1,7 +1,5 @@
package li.cil.oc.client.gui package li.cil.oc.client.gui
import java.util
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.client.Textures import li.cil.oc.client.Textures
import li.cil.oc.client.gui.widget.ProgressBar import li.cil.oc.client.gui.widget.ProgressBar
@ -51,8 +49,6 @@ class Drone(playerInventory: InventoryPlayer, val drone: entity.Drone) extends D
private val selectionsStates = 17 private val selectionsStates = 17
private val selectionStepV = 1 / selectionsStates.toDouble private val selectionStepV = 1 / selectionsStates.toDouble
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
protected override def actionPerformed(button: GuiButton) { protected override def actionPerformed(button: GuiButton) {
if (button.id == 0) { if (button.id == 0) {
ClientPacketSender.sendDronePower(drone, !drone.isRunning) ClientPacketSender.sendDronePower(drone, !drone.isRunning)
@ -61,9 +57,9 @@ class Drone(playerInventory: InventoryPlayer, val drone: entity.Drone) extends D
override def drawScreen(mouseX: Int, mouseY: Int, dt: Float) { override def drawScreen(mouseX: Int, mouseY: Int, dt: Float) {
powerButton.toggled = drone.isRunning powerButton.toggled = drone.isRunning
bufferRenderer.dirty = drone.statusText.lines.zipWithIndex.map { bufferRenderer.dirty = drone.statusText.lines.zipWithIndex.exists {
case (line, i) => buffer.set(0, i, line, vertical = false) case (line, i) => buffer.set(0, i, line, vertical = false)
}.contains(true) }
super.drawScreen(mouseX, mouseY, dt) super.drawScreen(mouseX, mouseY, dt)
} }

View File

@ -20,7 +20,7 @@ import org.lwjgl.opengl.GL11
import scala.collection.convert.WrapAsScala._ import scala.collection.convert.WrapAsScala._
abstract class DynamicGuiContainer(container: Container) extends CustomGuiContainer(container) { abstract class DynamicGuiContainer[C <: Container](container: C) extends CustomGuiContainer(container) {
protected var hoveredSlot: Option[Slot] = None protected var hoveredSlot: Option[Slot] = None
protected var hoveredStackNEI: Option[ItemStack] = None protected var hoveredStackNEI: Option[ItemStack] = None

View File

@ -1,7 +1,5 @@
package li.cil.oc.client.gui package li.cil.oc.client.gui
import java.util
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.client.Textures import li.cil.oc.client.Textures
@ -10,17 +8,15 @@ import li.cil.oc.client.renderer.markdown.segment.InteractiveSegment
import li.cil.oc.client.renderer.markdown.segment.Segment import li.cil.oc.client.renderer.markdown.segment.Segment
import li.cil.oc.client.{Manual => ManualAPI} import li.cil.oc.client.{Manual => ManualAPI}
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Gui
import net.minecraft.client.gui.GuiButton import net.minecraft.client.gui.GuiButton
import net.minecraft.client.gui.GuiScreen import net.minecraft.client.gui.GuiScreen
import net.minecraft.client.gui.ScaledResolution
import org.lwjgl.input.Mouse import org.lwjgl.input.Mouse
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._ import scala.collection.convert.WrapAsScala._
class Manual extends GuiScreen { class Manual extends GuiScreen with traits.Window {
final val documentMaxWidth = 230 final val documentMaxWidth = 230
final val documentMaxHeight = 176 final val documentMaxHeight = 176
final val scrollPosX = 244 final val scrollPosX = 244
@ -33,10 +29,11 @@ class Manual extends GuiScreen {
final val tabHeight = 26 final val tabHeight = 26
final val maxTabsPerSide = 7 final val maxTabsPerSide = 7
var guiLeft = 0 override val windowWidth = 256
var guiTop = 0 override val windowHeight = 192
var xSize = 0
var ySize = 0 override def backgroundImage = Textures.GUI.Manual
var isDragging = false var isDragging = false
var document: Segment = null var document: Segment = null
var documentHeight = 0 var documentHeight = 0
@ -49,8 +46,6 @@ class Manual extends GuiScreen {
def maxOffset = documentHeight - documentMaxHeight def maxOffset = documentHeight - documentMaxHeight
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
def resolveLink(path: String, current: String): String = def resolveLink(path: String, current: String): String =
if (path.startsWith("/")) path if (path.startsWith("/")) path
else { else {
@ -84,8 +79,6 @@ class Manual extends GuiScreen {
} }
} }
override def doesGuiPauseGame = false
override def actionPerformed(button: GuiButton): Unit = { override def actionPerformed(button: GuiButton): Unit = {
if (button.id >= 0 && button.id < ManualAPI.tabs.length) { if (button.id >= 0 && button.id < ManualAPI.tabs.length) {
api.Manual.navigate(ManualAPI.tabs(button.id).path) api.Manual.navigate(ManualAPI.tabs(button.id).path)
@ -95,14 +88,6 @@ class Manual extends GuiScreen {
override def initGui(): Unit = { override def initGui(): Unit = {
super.initGui() super.initGui()
val screenSize = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight)
val guiSize = new ScaledResolution(mc, 256, 192)
val (midX, midY) = (screenSize.getScaledWidth / 2, screenSize.getScaledHeight / 2)
guiLeft = midX - guiSize.getScaledWidth / 2
guiTop = midY - guiSize.getScaledHeight / 2
xSize = guiSize.getScaledWidth
ySize = guiSize.getScaledHeight
for ((tab, i) <- ManualAPI.tabs.zipWithIndex if i < maxTabsPerSide) { for ((tab, i) <- ManualAPI.tabs.zipWithIndex if i < maxTabsPerSide) {
val x = guiLeft + tabPosX val x = guiLeft + tabPosX
val y = guiTop + tabPosY + i * (tabHeight - 1) val y = guiTop + tabPosY + i * (tabHeight - 1)
@ -116,14 +101,11 @@ class Manual extends GuiScreen {
} }
override def drawScreen(mouseX: Int, mouseY: Int, dt: Float): Unit = { override def drawScreen(mouseX: Int, mouseY: Int, dt: Float): Unit = {
Textures.bind(Textures.GUI.Manual) super.drawScreen(mouseX, mouseY, dt)
Gui.drawModalRectWithCustomSizedTexture(guiLeft, guiTop, 0, 0, xSize, ySize, 256, 192)
scrollButton.enabled = canScroll scrollButton.enabled = canScroll
scrollButton.hoverOverride = isDragging scrollButton.hoverOverride = isDragging
super.drawScreen(mouseX, mouseY, dt)
for ((tab, i) <- ManualAPI.tabs.zipWithIndex if i < maxTabsPerSide) { for ((tab, i) <- ManualAPI.tabs.zipWithIndex if i < maxTabsPerSide) {
val button = buttonList.get(i).asInstanceOf[ImageButton] val button = buttonList.get(i).asInstanceOf[ImageButton]
GL11.glPushMatrix() GL11.glPushMatrix()

View File

@ -8,7 +8,6 @@ import li.cil.oc.common.container.ComponentSlot
import li.cil.oc.common.tileentity import li.cil.oc.common.tileentity
import li.cil.oc.util.RenderState import li.cil.oc.util.RenderState
import net.minecraft.entity.player.InventoryPlayer import net.minecraft.entity.player.InventoryPlayer
import org.lwjgl.opengl.GL11
class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer) extends DynamicGuiContainer(new container.Printer(playerInventory, printer)) { class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer) extends DynamicGuiContainer(new container.Printer(playerInventory, printer)) {
xSize = 176 xSize = 176
@ -36,8 +35,6 @@ class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer)
override def barTexture = Textures.GUI.PrinterProgress override def barTexture = Textures.GUI.PrinterProgress
}) })
private def printerContainer = inventorySlots.asInstanceOf[container.Printer]
override def initGui() { override def initGui() {
super.initGui() super.initGui()
} }
@ -50,12 +47,12 @@ class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer)
RenderState.pushAttrib() RenderState.pushAttrib()
if (isPointInRegion(materialBar.x, materialBar.y, materialBar.width, materialBar.height, mouseX, mouseY)) { if (isPointInRegion(materialBar.x, materialBar.y, materialBar.width, materialBar.height, mouseX, mouseY)) {
val tooltip = new java.util.ArrayList[String] val tooltip = new java.util.ArrayList[String]
tooltip.add(printerContainer.amountMaterial + "/" + printer.maxAmountMaterial) tooltip.add(inventoryContainer.amountMaterial + "/" + printer.maxAmountMaterial)
copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj) copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj)
} }
if (isPointInRegion(inkBar.x, inkBar.y, inkBar.width, inkBar.height, mouseX, mouseY)) { if (isPointInRegion(inkBar.x, inkBar.y, inkBar.width, inkBar.height, mouseX, mouseY)) {
val tooltip = new java.util.ArrayList[String] val tooltip = new java.util.ArrayList[String]
tooltip.add(printerContainer.amountInk + "/" + printer.maxAmountInk) tooltip.add(inventoryContainer.amountInk + "/" + printer.maxAmountInk)
copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj) copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj)
} }
RenderState.popAttrib() RenderState.popAttrib()
@ -65,14 +62,12 @@ class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer)
RenderState.color(1, 1, 1) RenderState.color(1, 1, 1)
Textures.bind(Textures.GUI.Printer) Textures.bind(Textures.GUI.Printer)
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize)
materialBar.level = printerContainer.amountMaterial / printer.maxAmountMaterial.toDouble materialBar.level = inventoryContainer.amountMaterial / printer.maxAmountMaterial.toDouble
inkBar.level = printerContainer.amountInk / printer.maxAmountInk.toDouble inkBar.level = inventoryContainer.amountInk / printer.maxAmountInk.toDouble
progressBar.level = printerContainer.progress progressBar.level = inventoryContainer.progress
drawWidgets() drawWidgets()
drawInventorySlots() drawInventorySlots()
} }
override protected def drawDisabledSlot(slot: ComponentSlot) {} override protected def drawDisabledSlot(slot: ComponentSlot) {}
override def doesGuiPauseGame = false
} }

View File

@ -1,7 +1,5 @@
package li.cil.oc.client.gui package li.cil.oc.client.gui
import java.util
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
@ -77,8 +75,6 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten
private val selectionsStates = 17 private val selectionsStates = 17
private val selectionStepV = 1 / selectionsStates.toDouble private val selectionStepV = 1 / selectionsStates.toDouble
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
protected override def actionPerformed(button: GuiButton) { protected override def actionPerformed(button: GuiButton) {
if (button.id == 0) { if (button.id == 0) {
ClientPacketSender.sendComputerPower(robot, !robot.isRunning) ClientPacketSender.sendComputerPower(robot, !robot.isRunning)

View File

@ -6,9 +6,10 @@ import li.cil.oc.common.container
import li.cil.oc.common.inventory.ServerInventory import li.cil.oc.common.inventory.ServerInventory
import li.cil.oc.util.RenderState import li.cil.oc.util.RenderState
import net.minecraft.entity.player.InventoryPlayer import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.inventory.Slot
class Server(playerInventory: InventoryPlayer, serverInventory: ServerInventory) extends DynamicGuiContainer(new container.Server(playerInventory, serverInventory)) { class Server(playerInventory: InventoryPlayer, serverInventory: ServerInventory) extends DynamicGuiContainer(new container.Server(playerInventory, serverInventory)) with traits.LockedHotbar {
override def lockedStack = serverInventory.container
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) { override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) {
super.drawSecondaryForegroundLayer(mouseX, mouseY) super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString( fontRendererObj.drawString(
@ -21,14 +22,4 @@ class Server(playerInventory: InventoryPlayer, serverInventory: ServerInventory)
Textures.bind(Textures.GUI.Server) Textures.bind(Textures.GUI.Server)
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize)
} }
override def doesGuiPauseGame = false
protected override def handleMouseClick(slot: Slot, slotNumber: Int, button: Int, shift: Int) {
if (slot == null || slot.getStack != serverInventory.container) {
super.handleMouseClick(slot, slotNumber, button, shift)
}
}
protected override def checkHotbarKeys(slot: Int) = false
} }

View File

@ -1,7 +1,5 @@
package li.cil.oc.client.gui package li.cil.oc.client.gui
import java.util
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.client.Textures import li.cil.oc.client.Textures
@ -35,8 +33,6 @@ class ServerRack(playerInventory: InventoryPlayer, val rack: tileentity.ServerRa
case _ => Localization.ServerRack.None case _ => Localization.ServerRack.None
} }
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
protected override def actionPerformed(button: GuiButton) { protected override def actionPerformed(button: GuiButton) {
if (button.id >= 0 && button.id <= 3) { if (button.id >= 0 && button.id <= 3) {
ClientPacketSender.sendServerPower(rack, button.id, !rack.isRunning(button.id)) ClientPacketSender.sendServerPower(rack, button.id, !rack.isRunning(button.id))
@ -46,7 +42,7 @@ class ServerRack(playerInventory: InventoryPlayer, val rack: tileentity.ServerRa
val sides = EnumFacing.values.map(Option(_)) ++ Seq(None) val sides = EnumFacing.values.map(Option(_)) ++ Seq(None)
val currentSide = sides.indexOf(rack.sides(number)) val currentSide = sides.indexOf(rack.sides(number))
val searchSides = sides.drop(currentSide + 1) ++ sides.take(currentSide + 1) val searchSides = sides.drop(currentSide + 1) ++ sides.take(currentSide + 1)
val nextSide = searchSides.find(side => side != Option(EnumFacing.SOUTH) && (!rack.sides.contains(side) || side == None)) match { val nextSide = searchSides.find(side => side != Option(EnumFacing.SOUTH) && (!rack.sides.contains(side) || side.isEmpty)) match {
case Some(side) => side case Some(side) => side
case _ => None case _ => None
} }

View File

@ -8,7 +8,6 @@ import li.cil.oc.common.tileentity
import net.minecraft.entity.player.InventoryPlayer import net.minecraft.entity.player.InventoryPlayer
class Switch(playerInventory: InventoryPlayer, val switch: tileentity.Switch) extends DynamicGuiContainer(new container.Switch(playerInventory, switch)) { class Switch(playerInventory: InventoryPlayer, val switch: tileentity.Switch) extends DynamicGuiContainer(new container.Switch(playerInventory, switch)) {
private val switchContainer = inventorySlots.asInstanceOf[container.Switch]
private val format = new DecimalFormat("#.##hz") private val format = new DecimalFormat("#.##hz")
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
@ -28,14 +27,14 @@ class Switch(playerInventory: InventoryPlayer, val switch: tileentity.Switch) ex
14, 58, 0x404040) 14, 58, 0x404040)
fontRendererObj.drawString( fontRendererObj.drawString(
format.format(20f / switchContainer.relayDelay), format.format(20f / inventoryContainer.relayDelay),
108, 20, 0x404040) 108, 20, 0x404040)
fontRendererObj.drawString( fontRendererObj.drawString(
switchContainer.packetsPerCycleAvg + " / " + switchContainer.relayAmount, inventoryContainer.packetsPerCycleAvg + " / " + inventoryContainer.relayAmount,
108, 39, thresholdBasedColor(switchContainer.packetsPerCycleAvg, math.ceil(switchContainer.relayAmount / 2f).toInt, switchContainer.relayAmount)) 108, 39, thresholdBasedColor(inventoryContainer.packetsPerCycleAvg, math.ceil(inventoryContainer.relayAmount / 2f).toInt, inventoryContainer.relayAmount))
fontRendererObj.drawString( fontRendererObj.drawString(
switchContainer.queueSize + " / " + switchContainer.maxQueueSize, inventoryContainer.queueSize + " / " + inventoryContainer.maxQueueSize,
108, 58, thresholdBasedColor(switchContainer.queueSize, switchContainer.maxQueueSize / 2, switchContainer.maxQueueSize)) 108, 58, thresholdBasedColor(inventoryContainer.queueSize, inventoryContainer.maxQueueSize / 2, inventoryContainer.maxQueueSize))
} }
private def thresholdBasedColor(value: Int, yellow: Int, red: Int) = { private def thresholdBasedColor(value: Int, yellow: Int, red: Int) = {

View File

@ -4,23 +4,14 @@ import li.cil.oc.Localization
import li.cil.oc.common.container import li.cil.oc.common.container
import li.cil.oc.common.item.TabletWrapper import li.cil.oc.common.item.TabletWrapper
import net.minecraft.entity.player.InventoryPlayer import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.inventory.Slot
class Tablet(playerInventory: InventoryPlayer, val tablet: TabletWrapper) extends DynamicGuiContainer(new container.Tablet(playerInventory, tablet)) { class Tablet(playerInventory: InventoryPlayer, val tablet: TabletWrapper) extends DynamicGuiContainer(new container.Tablet(playerInventory, tablet)) with traits.LockedHotbar {
override def lockedStack = tablet.stack
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = { override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY) super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString( fontRendererObj.drawString(
Localization.localizeImmediately(tablet.getName), Localization.localizeImmediately(tablet.getName),
8, 6, 0x404040) 8, 6, 0x404040)
} }
override def doesGuiPauseGame = false
protected override def handleMouseClick(slot: Slot, slotNumber: Int, button: Int, shift: Int) {
if (slot == null || slot.getStack != tablet.stack) {
super.handleMouseClick(slot, slotNumber, button, shift)
}
}
protected override def checkHotbarKeys(slot: Int) = false
} }

View File

@ -0,0 +1,17 @@
package li.cil.oc.client.gui.traits
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.inventory.Slot
import net.minecraft.item.ItemStack
trait LockedHotbar extends GuiContainer {
def lockedStack: ItemStack
protected override def handleMouseClick(slot: Slot, slotNumber: Int, button: Int, shift: Int) {
if (slot == null || slot.getStack != lockedStack) {
super.handleMouseClick(slot, slotNumber, button, shift)
}
}
protected override def checkHotbarKeys(keyCode: Int) = false
}

View File

@ -0,0 +1,44 @@
package li.cil.oc.client.gui.traits
import java.util
import net.minecraft.client.gui.Gui
import net.minecraft.client.gui.GuiScreen
import net.minecraft.client.gui.ScaledResolution
import net.minecraft.util.ResourceLocation
trait Window extends GuiScreen {
var guiLeft = 0
var guiTop = 0
var xSize = 0
var ySize = 0
val windowWidth = 176
val windowHeight = 166
def backgroundImage: ResourceLocation
protected def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
override def doesGuiPauseGame = false
override def initGui(): Unit = {
super.initGui()
val screenSize = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight)
val guiSize = new ScaledResolution(mc, windowWidth, windowHeight)
val (midX, midY) = (screenSize.getScaledWidth / 2, screenSize.getScaledHeight / 2)
guiLeft = midX - guiSize.getScaledWidth / 2
guiTop = midY - guiSize.getScaledHeight / 2
xSize = guiSize.getScaledWidth
ySize = guiSize.getScaledHeight
}
override def drawScreen(mouseX: Int, mouseY: Int, dt: Float): Unit = {
mc.renderEngine.bindTexture(backgroundImage)
Gui.drawModalRectWithCustomSizedTexture(guiLeft, guiTop, 0, 0, xSize, ySize, windowWidth, windowHeight)
super.drawScreen(mouseX, mouseY, dt)
}
}

View File

@ -303,8 +303,12 @@ object EventHandler {
else false else false
} }
// This is called from the ServerThread *and* the ClientShutdownThread, which
// can potentially happen at the same time... for whatever reason. So let's
// synchronize what we're doing here to avoid race conditions (e.g. when
// disposing networks, where this actually triggered an assert).
@SubscribeEvent @SubscribeEvent
def onWorldUnload(e: WorldEvent.Unload) { def onWorldUnload(e: WorldEvent.Unload): Unit = this.synchronized {
if (!e.world.isRemote) { if (!e.world.isRemote) {
e.world.loadedTileEntityList.collect { e.world.loadedTileEntityList.collect {
case te: tileentity.traits.TileEntity => te.dispose() case te: tileentity.traits.TileEntity => te.dispose()

View File

@ -22,6 +22,7 @@ object GuiType extends ScalaEnum {
val Database = new EnumVal { def name = "Database"; def subType = GuiType.Category.Item } val Database = new EnumVal { def name = "Database"; def subType = GuiType.Category.Item }
val Disassembler = new EnumVal { def name = "Disassembler"; def subType = GuiType.Category.Block } val Disassembler = new EnumVal { def name = "Disassembler"; def subType = GuiType.Category.Block }
val DiskDrive = new EnumVal { def name = "DiskDrive"; def subType = GuiType.Category.Block } val DiskDrive = new EnumVal { def name = "DiskDrive"; def subType = GuiType.Category.Block }
val Drive = new EnumVal { def name = "Drive"; def subType = GuiType.Category.Item }
val Drone = new EnumVal { def name = "Drone"; def subType = GuiType.Category.Entity } val Drone = new EnumVal { def name = "Drone"; def subType = GuiType.Category.Entity }
val Manual = new EnumVal { def name = "Manual"; def subType = GuiType.Category.None } val Manual = new EnumVal { def name = "Manual"; def subType = GuiType.Category.None }
val Printer = new EnumVal { def name = "Printer"; def subType = GuiType.Category.Block } val Printer = new EnumVal { def name = "Printer"; def subType = GuiType.Category.Block }

View File

@ -59,6 +59,7 @@ object PacketType extends Enumeration {
// Client -> Server // Client -> Server
ComputerPower, ComputerPower,
CopyToAnalyzer, CopyToAnalyzer,
DriveMode,
DronePower, DronePower,
KeyDown, KeyDown,
KeyUp, KeyUp,

View File

@ -232,7 +232,7 @@ object SaveHandler {
// systems, to avoid deleting in-use folders here. // systems, to avoid deleting in-use folders here.
System.currentTimeMillis() - file.lastModified() > TimeToHoldOntoOldSaves && { System.currentTimeMillis() - file.lastModified() > TimeToHoldOntoOldSaves && {
val list = file.list() val list = file.list()
list == null || list.length == 0 list == null || list.isEmpty
} }
}) })
if (emptyDirs != null) { if (emptyDirs != null) {

View File

@ -1,32 +1,19 @@
package li.cil.oc.common.item package li.cil.oc.common.item
import java.util
import li.cil.oc.Constants import li.cil.oc.Constants
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.util.Color import li.cil.oc.util.Color
import net.minecraft.client.resources.model.ModelBakery import net.minecraft.client.resources.model.ModelBakery
import net.minecraft.client.resources.model.ModelResourceLocation import net.minecraft.client.resources.model.ModelResourceLocation
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly import net.minecraftforge.fml.relauncher.SideOnly
class FloppyDisk(val parent: Delegator) extends traits.Delegate with CustomModel { class FloppyDisk(val parent: Delegator) extends traits.Delegate with CustomModel with traits.FileSystemLike {
// Necessary for anonymous subclasses used for loot disks. // Necessary for anonymous subclasses used for loot disks.
override def unlocalizedName = "FloppyDisk" override def unlocalizedName = "FloppyDisk"
override protected def tooltipName = None val kiloBytes = Settings.get.floppySize
override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) = {
if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "data")) {
val nbt = stack.getTagCompound.getCompoundTag(Settings.namespace + "data")
if (nbt.hasKey(Settings.namespace + "fs.label")) {
tooltip.add(nbt.getString(Settings.namespace + "fs.label"))
}
}
super.tooltipLines(stack, player, tooltip, advanced)
}
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
private def modelLocationFromDyeName(name: String) = { private def modelLocationFromDyeName(name: String) = {

View File

@ -1,36 +1,12 @@
package li.cil.oc.common.item package li.cil.oc.common.item
import java.util
import li.cil.oc.Settings import li.cil.oc.Settings
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
class HardDiskDrive(val parent: Delegator, val tier: Int) extends traits.Delegate with traits.ItemTier { class HardDiskDrive(val parent: Delegator, val tier: Int) extends traits.Delegate with traits.ItemTier with traits.FileSystemLike {
override val unlocalizedName = super.unlocalizedName + tier override val unlocalizedName = super.unlocalizedName + tier
val kiloBytes = Settings.get.hddSizes(tier) val kiloBytes = Settings.get.hddSizes(tier)
val platterCount = Settings.get.hddPlatterCounts(tier)
override protected def tooltipName = None
override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) = {
if (stack.hasTagCompound) {
val nbt = stack.getTagCompound
if (nbt.hasKey(Settings.namespace + "data")) {
val data = nbt.getCompoundTag(Settings.namespace + "data")
if (data.hasKey(Settings.namespace + "fs.label")) {
tooltip.add(data.getString(Settings.namespace + "fs.label"))
}
if (advanced && data.hasKey("fs")) {
val fsNbt = data.getCompoundTag("fs")
if (fsNbt.hasKey("capacity.used")) {
val used = fsNbt.getLong("capacity.used")
tooltip.add(s"Disk usage: $used/${kiloBytes * 1024} Byte")
}
}
}
}
super.tooltipLines(stack, player, tooltip, advanced)
}
override def displayName(stack: ItemStack) = { override def displayName(stack: ItemStack) = {
val localizedName = parent.internalGetItemStackDisplayName(stack) val localizedName = parent.internalGetItemStackDisplayName(stack)

View File

@ -0,0 +1,22 @@
package li.cil.oc.common.item.data
import li.cil.oc.Settings
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
class DriveData extends ItemData(null) {
def this(stack: ItemStack) {
this()
load(stack)
}
var isUnmanaged = false
override def load(nbt: NBTTagCompound) {
isUnmanaged = nbt.getBoolean(Settings.namespace + "unmanaged")
}
override def save(nbt: NBTTagCompound) {
nbt.setBoolean(Settings.namespace + "unmanaged", isUnmanaged)
}
}

View File

@ -0,0 +1,46 @@
package li.cil.oc.common.item.traits
import java.util
import li.cil.oc.Localization
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.common.GuiType
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.world.World
trait FileSystemLike extends Delegate {
override protected def tooltipName = None
def kiloBytes: Int
override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) = {
if (stack.hasTagCompound) {
val nbt = stack.getTagCompound
if (nbt.hasKey(Settings.namespace + "data")) {
val data = nbt.getCompoundTag(Settings.namespace + "data")
if (data.hasKey(Settings.namespace + "fs.label")) {
tooltip.add(data.getString(Settings.namespace + "fs.label"))
}
if (advanced && data.hasKey("fs")) {
val fsNbt = data.getCompoundTag("fs")
if (fsNbt.hasKey("capacity.used")) {
val used = fsNbt.getLong("capacity.used")
tooltip.add(Localization.Tooltip.DiskUsage(used, kiloBytes * 1024))
}
}
}
tooltip.add(Localization.Tooltip.DiskMode(nbt.getBoolean(Settings.namespace + "unmanaged")))
}
super.tooltipLines(stack, player, tooltip, advanced)
}
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
if (!player.isSneaking) {
player.openGui(OpenComputers, GuiType.Drive.id, world, 0, 0, 0)
player.swingItem()
}
stack
}
}

View File

@ -10,6 +10,8 @@ import li.cil.oc.common.Slot
import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.Delegator
import li.cil.oc.common.item.FloppyDisk import li.cil.oc.common.item.FloppyDisk
import li.cil.oc.common.item.HardDiskDrive import li.cil.oc.common.item.HardDiskDrive
import li.cil.oc.common.item.data.DriveData
import li.cil.oc.server.component.Drive
import li.cil.oc.server.fs.FileSystem.ItemLabel import li.cil.oc.server.fs.FileSystem.ItemLabel
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
@ -25,8 +27,8 @@ object DriverFileSystem extends Item {
override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = override def createEnvironment(stack: ItemStack, host: EnvironmentHost) =
Delegator.subItem(stack) match { Delegator.subItem(stack) match {
case Some(hdd: HardDiskDrive) => createEnvironment(stack, hdd.kiloBytes * 1024, host, hdd.tier + 2) case Some(hdd: HardDiskDrive) => createEnvironment(stack, hdd.kiloBytes * 1024, hdd.platterCount, host, hdd.tier + 2)
case Some(disk: FloppyDisk) => createEnvironment(stack, Settings.get.floppySize * 1024, host, 1) case Some(disk: FloppyDisk) => createEnvironment(stack, Settings.get.floppySize * 1024, 1, host, 1)
case _ => null case _ => null
} }
@ -43,7 +45,7 @@ object DriverFileSystem extends Item {
case _ => 0 case _ => 0
} }
private def createEnvironment(stack: ItemStack, capacity: Int, host: EnvironmentHost, speed: Int) = if (DimensionManager.getWorld(0) != null) { private def createEnvironment(stack: ItemStack, capacity: Int, platterCount: Int, host: EnvironmentHost, speed: Int) = if (DimensionManager.getWorld(0) != null) {
if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "lootFactory")) { if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "lootFactory")) {
// Loot disk, create file system using factory callback. // Loot disk, create file system using factory callback.
Loot.factories.get(stack.getTagCompound.getString(Settings.namespace + "lootFactory")) match { Loot.factories.get(stack.getTagCompound.getString(Settings.namespace + "lootFactory")) match {
@ -61,9 +63,17 @@ object DriverFileSystem extends Item {
// node's address as the folder name... so we generate the address here, // node's address as the folder name... so we generate the address here,
// if necessary. No one will know, right? Right!? // if necessary. No one will know, right? Right!?
val address = addressFromTag(dataTag(stack)) val address = addressFromTag(dataTag(stack))
val label = new ReadWriteItemLabel(stack)
val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy) val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy)
val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges) val sound = Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access")
val environment = oc.api.FileSystem.asManagedEnvironment(fs, new ReadWriteItemLabel(stack), host, Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access"), speed) val drive = new DriveData(stack)
val environment = if (drive.isUnmanaged) {
Drive(capacity, platterCount, label, Option(host), Option(sound), speed)
}
else {
val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges)
oc.api.FileSystem.asManagedEnvironment(fs, label, host, sound, speed)
}
if (environment != null && environment.node != null) { if (environment != null && environment.node != null) {
environment.node.asInstanceOf[oc.server.network.Node].address = address environment.node.asInstanceOf[oc.server.network.Node].address = address
} }

View File

@ -8,6 +8,9 @@ import li.cil.oc.common.Achievement
import li.cil.oc.common.PacketType import li.cil.oc.common.PacketType
import li.cil.oc.common.component.TextBuffer import li.cil.oc.common.component.TextBuffer
import li.cil.oc.common.entity.Drone import li.cil.oc.common.entity.Drone
import li.cil.oc.common.item.Delegator
import li.cil.oc.common.item.data.DriveData
import li.cil.oc.common.item.traits.FileSystemLike
import li.cil.oc.common.tileentity._ import li.cil.oc.common.tileentity._
import li.cil.oc.common.tileentity.traits.Computer import li.cil.oc.common.tileentity.traits.Computer
import li.cil.oc.common.tileentity.traits.TileEntity import li.cil.oc.common.tileentity.traits.TileEntity
@ -38,6 +41,7 @@ object PacketHandler extends CommonPacketHandler {
p.packetType match { p.packetType match {
case PacketType.ComputerPower => onComputerPower(p) case PacketType.ComputerPower => onComputerPower(p)
case PacketType.CopyToAnalyzer => onCopyToAnalyzer(p) case PacketType.CopyToAnalyzer => onCopyToAnalyzer(p)
case PacketType.DriveMode => onDriveMode(p)
case PacketType.DronePower => onDronePower(p) case PacketType.DronePower => onDronePower(p)
case PacketType.KeyDown => onKeyDown(p) case PacketType.KeyDown => onKeyDown(p)
case PacketType.KeyUp => onKeyUp(p) case PacketType.KeyUp => onKeyUp(p)
@ -83,6 +87,18 @@ object PacketHandler extends CommonPacketHandler {
} }
} }
def onDriveMode(p: PacketParser) = p.player match {
case player: EntityPlayerMP =>
Delegator.subItem(player.getCurrentEquippedItem) match {
case Some(drive: FileSystemLike) =>
val data = new DriveData(player.getCurrentEquippedItem)
data.isUnmanaged = p.readBoolean()
data.save(player.getCurrentEquippedItem)
case _ => // Invalid packet.
}
case _ => // Invalid packet.
}
def onDronePower(p: PacketParser) = def onDronePower(p: PacketParser) =
p.readEntity[Drone]() match { p.readEntity[Drone]() match {
case Some(drone) => p.player match { case Some(drone) => p.player match {

View File

@ -0,0 +1,268 @@
package li.cil.oc.server.component
import java.io
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
import com.google.common.io.Files
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.api.Network
import li.cil.oc.api.driver.EnvironmentHost
import li.cil.oc.api.fs.Label
import li.cil.oc.api.machine.Arguments
import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context
import li.cil.oc.api.network.Visibility
import li.cil.oc.api.prefab
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.DimensionManager
class Drive(val capacity: Int, val platterCount: Int, val label: Label, host: Option[EnvironmentHost], val sound: Option[String]) extends prefab.ManagedEnvironment {
override val node = Network.newNode(this, Visibility.Network).
withComponent("drive", Visibility.Neighbors).
withConnector().
create()
private def savePath = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + node.address + ".bin")
private final val sectorSize = 512
private val data = new Array[Byte](capacity)
private val sectorCount = capacity / sectorSize
private val sectorsPerPlatter = sectorCount / platterCount
private var headPos = 0
// ----------------------------------------------------------------------- //
@Callback(direct = true, doc = """function():string -- Get the current label of the drive.""")
def getLabel(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
if (label != null) result(label.getLabel) else null
}
@Callback(doc = """function(value:string):string -- Sets the label of the drive. Returns the new value, which may be truncated.""")
def setLabel(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
if (label == null) throw new Exception("drive does not support labeling")
if (args.checkAny(0) == null) label.setLabel(null)
else label.setLabel(args.checkString(0))
result(label.getLabel)
}
@Callback(direct = true, doc = """function():number -- Returns the total capacity of the drive, in bytes.""")
def getCapacity(context: Context, args: Arguments): Array[AnyRef] = result(capacity)
@Callback(direct = true, doc = """function():number -- Returns the size of a single sector on the drive, in bytes.""")
def getSectorSize(context: Context, args: Arguments): Array[AnyRef] = result(sectorSize)
@Callback(direct = true, doc = """function():number -- Returns the number of platters in the drive.""")
def getPlatterCount(context: Context, args: Arguments): Array[AnyRef] = result(platterCount)
def readSector(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
val sector = moveToSector(context, checkSector(args, 0))
diskActivity()
val sectorData = new Array[Byte](sectorSize)
Array.copy(data, sectorOffset(sector), sectorData, 0, sectorSize)
result(sectorData)
}
def writeSector(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
val sectorData = args.checkByteArray(1)
val sector = moveToSector(context, checkSector(args, 0))
diskActivity()
Array.copy(sectorData, 0, data, sectorOffset(sector), math.min(sectorSize, sectorData.length))
null
}
def readByte(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
val offset = args.checkInteger(0) - 1
moveToSector(context, checkSector(offset))
diskActivity()
result(data(offset))
}
def writeByte(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
val offset = args.checkInteger(0) - 1
val value = args.checkInteger(1).toByte
moveToSector(context, checkSector(offset))
diskActivity()
data(offset) = value
null
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) = this.synchronized {
super.load(nbt)
if (node.address != null) try {
val path = savePath
if (path.exists()) {
val bin = new ByteArrayInputStream(Files.toByteArray(path))
val zin = new GZIPInputStream(bin)
var offset = 0
var read = 0
while (read >= 0 && offset < data.length) {
read = zin.read(data, offset, data.length - offset)
offset += read
}
}
}
catch {
case t: Throwable => OpenComputers.log.warn(s"Failed loading drive contents for '${node.address}'.", t)
}
headPos = nbt.getInteger("headPos") max 0 min sectorToHeadPos(sectorCount)
if (label != null) {
label.load(nbt)
}
}
override def save(nbt: NBTTagCompound) = this.synchronized {
super.save(nbt)
if (node.address != null) try {
val path = savePath
path.getParentFile.mkdirs()
val bos = new ByteArrayOutputStream()
val zos = new GZIPOutputStream(bos)
zos.write(data)
zos.close()
Files.write(bos.toByteArray, path)
}
catch {
case t: Throwable => OpenComputers.log.warn(s"Failed saving drive contents for '${node.address}'.", t)
}
nbt.setInteger("headPos", headPos)
if (label != null) {
label.save(nbt)
}
}
// ----------------------------------------------------------------------- //
private def validateSector(sector: Int) = {
if (sector < 0 || sector >= sectorCount)
throw new IllegalArgumentException("invalid offset, not in a usable sector")
sector
}
private def checkSector(offset: Int) = validateSector(offsetSector(offset))
private def checkSector(args: Arguments, n: Int) = validateSector(args.checkInteger(n) - 1)
private def moveToSector(context: Context, sector: Int) = {
val newHeadPos = sectorToHeadPos(sector)
if (headPos != newHeadPos) {
val delta = math.abs(headPos - newHeadPos)
if (delta > Settings.get.sectorSeekThreshold) context.pause(Settings.get.sectorSeekTime)
headPos = newHeadPos
}
sector
}
private def sectorToHeadPos(sector: Int) = sector % sectorsPerPlatter
private def sectorOffset(sector: Int) = sector * sectorSize
private def offsetSector(offset: Int) = offset / sectorSize
private def diskActivity() {
(sound, host) match {
case (Some(s), Some(h)) => ServerPacketSender.sendFileSystemActivity(node, h, s)
case _ =>
}
}
}
object Drive {
// I really need to come up with a way to make the call limit dynamic...
def apply(capacity: Int, platterCount: Int, label: Label, host: Option[EnvironmentHost], sound: Option[String], speed: Int = 1): Drive = speed match {
case 6 => new Drive(capacity, platterCount, label, host, sound) {
@Callback(direct = true, limit = 60, doc = """function(sector:number):string -- Read the current contents of the specified sector.""")
override def readSector(context: Context, args: Arguments): Array[AnyRef] = super.readSector(context, args)
@Callback(direct = true, limit = 30, doc = """function(sector:number, value:string) -- Write the specified contents to the specified sector.""")
override def writeSector(context: Context, args: Arguments): Array[AnyRef] = super.writeSector(context, args)
@Callback(direct = true, limit = 128, doc = """function(offset:number):number -- Read a single byte at the specified offset.""")
override def readByte(context: Context, args: Arguments): Array[AnyRef] = super.readByte(context, args)
@Callback(direct = true, limit = 64, doc = """function(offset:number, value:number) -- Write a single byte to the specified offset.""")
override def writeByte(context: Context, args: Arguments): Array[AnyRef] = super.writeByte(context, args)
}
case 5 => new Drive(capacity, platterCount, label, host, sound) {
@Callback(direct = true, limit = 50, doc = """function(sector:number):string -- Read the current contents of the specified sector.""")
override def readSector(context: Context, args: Arguments): Array[AnyRef] = super.readSector(context, args)
@Callback(direct = true, limit = 25, doc = """function(sector:number, value:string) -- Write the specified contents to the specified sector.""")
override def writeSector(context: Context, args: Arguments): Array[AnyRef] = super.writeSector(context, args)
@Callback(direct = true, limit = 112, doc = """function(offset:number):number -- Read a single byte at the specified offset.""")
override def readByte(context: Context, args: Arguments): Array[AnyRef] = super.readByte(context, args)
@Callback(direct = true, limit = 56, doc = """function(offset:number, value:number) -- Write a single byte to the specified offset.""")
override def writeByte(context: Context, args: Arguments): Array[AnyRef] = super.writeByte(context, args)
}
case 4 => new Drive(capacity, platterCount, label, host, sound) {
@Callback(direct = true, limit = 40, doc = """function(sector:number):string -- Read the current contents of the specified sector.""")
override def readSector(context: Context, args: Arguments): Array[AnyRef] = super.readSector(context, args)
@Callback(direct = true, limit = 20, doc = """function(sector:number, value:string) -- Write the specified contents to the specified sector.""")
override def writeSector(context: Context, args: Arguments): Array[AnyRef] = super.writeSector(context, args)
@Callback(direct = true, limit = 96, doc = """function(offset:number):number -- Read a single byte at the specified offset.""")
override def readByte(context: Context, args: Arguments): Array[AnyRef] = super.readByte(context, args)
@Callback(direct = true, limit = 48, doc = """function(offset:number, value:number) -- Write a single byte to the specified offset.""")
override def writeByte(context: Context, args: Arguments): Array[AnyRef] = super.writeByte(context, args)
}
case 3 => new Drive(capacity, platterCount, label, host, sound) {
@Callback(direct = true, limit = 30, doc = """function(sector:number):string -- Read the current contents of the specified sector.""")
override def readSector(context: Context, args: Arguments): Array[AnyRef] = super.readSector(context, args)
@Callback(direct = true, limit = 15, doc = """function(sector:number, value:string) -- Write the specified contents to the specified sector.""")
override def writeSector(context: Context, args: Arguments): Array[AnyRef] = super.writeSector(context, args)
@Callback(direct = true, limit = 80, doc = """function(offset:number):number -- Read a single byte at the specified offset.""")
override def readByte(context: Context, args: Arguments): Array[AnyRef] = super.readByte(context, args)
@Callback(direct = true, limit = 40, doc = """function(offset:number, value:number) -- Write a single byte to the specified offset.""")
override def writeByte(context: Context, args: Arguments): Array[AnyRef] = super.writeByte(context, args)
}
case 2 => new Drive(capacity, platterCount, label, host, sound) {
@Callback(direct = true, limit = 20, doc = """function(sector:number):string -- Read the current contents of the specified sector.""")
override def readSector(context: Context, args: Arguments): Array[AnyRef] = super.readSector(context, args)
@Callback(direct = true, limit = 10, doc = """function(sector:number, value:string) -- Write the specified contents to the specified sector.""")
override def writeSector(context: Context, args: Arguments): Array[AnyRef] = super.writeSector(context, args)
@Callback(direct = true, limit = 64, doc = """function(offset:number):number -- Read a single byte at the specified offset.""")
override def readByte(context: Context, args: Arguments): Array[AnyRef] = super.readByte(context, args)
@Callback(direct = true, limit = 32, doc = """function(offset:number, value:number) -- Write a single byte to the specified offset.""")
override def writeByte(context: Context, args: Arguments): Array[AnyRef] = super.writeByte(context, args)
}
case _ => new Drive(capacity, platterCount, label, host, sound) {
@Callback(direct = true, limit = 10, doc = """function(sector:number):string -- Read the current contents of the specified sector.""")
override def readSector(context: Context, args: Arguments): Array[AnyRef] = super.readSector(context, args)
@Callback(direct = true, limit = 5, doc = """function(sector:number, value:string) -- Write the specified contents to the specified sector.""")
override def writeSector(context: Context, args: Arguments): Array[AnyRef] = super.writeSector(context, args)
@Callback(direct = true, limit = 48, doc = """function(offset:number):number -- Read a single byte at the specified offset.""")
override def readByte(context: Context, args: Arguments): Array[AnyRef] = super.readByte(context, args)
@Callback(direct = true, limit = 24, doc = """function(offset:number, value:number) -- Write a single byte to the specified offset.""")
override def writeByte(context: Context, args: Arguments): Array[AnyRef] = super.writeByte(context, args)
}
}
}

View File

@ -33,14 +33,14 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback(direct = true, doc = """function():string -- Get the current label of the file system.""") @Callback(direct = true, doc = """function():string -- Get the current label of the drive.""")
def getLabel(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { def getLabel(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
if (label != null) result(label.getLabel) else null if (label != null) result(label.getLabel) else null
} }
@Callback(doc = """function(value:string):string -- Sets the label of the file system. Returns the new value, which may be truncated.""") @Callback(doc = """function(value:string):string -- Sets the label of the drive. Returns the new value, which may be truncated.""")
def setLabel(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { def setLabel(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
if (label == null) throw new Exception("filesystem does not support labeling") if (label == null) throw new Exception("drive does not support labeling")
if (args.checkAny(0) == null) label.setLabel(null) if (args.checkAny(0) == null) label.setLabel(null)
else label.setLabel(args.checkString(0)) else label.setLabel(args.checkString(0))
result(label.getLabel) result(label.getLabel)

View File

@ -123,6 +123,7 @@ private[oc] object Registry extends api.detail.DriverAPI {
case arg: java.lang.Long => arg case arg: java.lang.Long => arg
case arg: java.lang.Float => arg case arg: java.lang.Float => arg
case arg: java.lang.Double => arg case arg: java.lang.Double => arg
case arg: java.lang.Number => Double.box(arg.doubleValue())
case arg: java.lang.String => arg case arg: java.lang.String => arg
case arg: Array[Boolean] => arg case arg: Array[Boolean] => arg

View File

@ -72,7 +72,7 @@ trait Buffered extends OutputStreamFileSystem {
} }
setLastModified(path, directory.lastModified()) setLastModified(path, directory.lastModified())
} }
if (fileRoot.list() == null || fileRoot.list().length == 0) { if (fileRoot.list() == null || fileRoot.list().isEmpty) {
fileRoot.delete() fileRoot.delete()
} }
else recurse("", fileRoot) else recurse("", fileRoot)
@ -114,7 +114,7 @@ trait Buffered extends OutputStreamFileSystem {
} }
directory.setLastModified(lastModified(path)) directory.setLastModified(lastModified(path))
} }
if (list("") == null || list("").length == 0) { if (list("") == null || list("").isEmpty) {
fileRoot.delete() fileRoot.delete()
} }
else recurse("") else recurse("")

View File

@ -303,13 +303,9 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
signals.enqueue(new Machine.Signal(name, args.map { signals.enqueue(new Machine.Signal(name, args.map {
case null | Unit | None => null case null | Unit | None => null
case arg: java.lang.Boolean => arg case arg: java.lang.Boolean => arg
case arg: java.lang.Byte => Double.box(arg.doubleValue)
case arg: java.lang.Character => Double.box(arg.toDouble) case arg: java.lang.Character => Double.box(arg.toDouble)
case arg: java.lang.Short => Double.box(arg.doubleValue) case arg: java.lang.Long => arg
case arg: java.lang.Integer => Double.box(arg.doubleValue) case arg: java.lang.Number => Double.box(arg.doubleValue)
case arg: java.lang.Long => Double.box(arg.doubleValue)
case arg: java.lang.Float => Double.box(arg.doubleValue)
case arg: java.lang.Double => arg
case arg: java.lang.String => arg case arg: java.lang.String => arg
case arg: Array[Byte] => arg case arg: Array[Byte] => arg
case arg: Map[_, _] if arg.isEmpty || arg.head._1.isInstanceOf[String] && arg.head._2.isInstanceOf[String] => arg case arg: Map[_, _] if arg.isEmpty || arg.head._1.isInstanceOf[String] && arg.head._2.isInstanceOf[String] => arg
@ -697,6 +693,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
(0 until argsLength).map("arg" + _).map(argsNbt.getTag).map { (0 until argsLength).map("arg" + _).map(argsNbt.getTag).map {
case tag: NBTTagByte if tag.getByte == -1 => null case tag: NBTTagByte if tag.getByte == -1 => null
case tag: NBTTagByte => Boolean.box(tag.getByte == 1) case tag: NBTTagByte => Boolean.box(tag.getByte == 1)
case tag: NBTTagLong => Long.box(tag.getLong)
case tag: NBTTagDouble => Double.box(tag.getDouble) case tag: NBTTagDouble => Double.box(tag.getDouble)
case tag: NBTTagString => tag.getString case tag: NBTTagString => tag.getString
case tag: NBTTagByteArray => tag.getByteArray case tag: NBTTagByteArray => tag.getByteArray
@ -770,6 +767,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
s.args.zipWithIndex.foreach { s.args.zipWithIndex.foreach {
case (null, i) => args.setByte("arg" + i, -1) case (null, i) => args.setByte("arg" + i, -1)
case (arg: java.lang.Boolean, i) => args.setByte("arg" + i, if (arg) 1 else 0) case (arg: java.lang.Boolean, i) => args.setByte("arg" + i, if (arg) 1 else 0)
case (arg: java.lang.Long, i) => args.setLong("arg" + i, arg)
case (arg: java.lang.Double, i) => args.setDouble("arg" + i, arg) case (arg: java.lang.Double, i) => args.setDouble("arg" + i, arg)
case (arg: String, i) => args.setString("arg" + i, arg) case (arg: String, i) => args.setString("arg" + i, arg)
case (arg: Array[Byte], i) => args.setByteArray("arg" + i, arg) case (arg: Array[Byte], i) => args.setByteArray("arg" + i, arg)