mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-09 23:38:04 -04:00
Merge branch 'master-MC1.10' into master-MC1.12
# Conflicts: # src/main/resources/assets/opencomputers/lang/en_US.lang # src/main/scala/li/cil/oc/Localization.scala # src/main/scala/li/cil/oc/common/component/TextBuffer.scala # src/main/scala/li/cil/oc/common/init/Items.scala # src/main/scala/li/cil/oc/server/component/GraphicsCard.scala # src/main/scala/li/cil/oc/server/component/Trade.scala
This commit is contained in:
commit
012f55a7fa
@ -244,16 +244,6 @@ opencomputers {
|
|||||||
1024
|
1024
|
||||||
]
|
]
|
||||||
|
|
||||||
# Video ram can be allocated on a gpu. The amount of vram you can allocate
|
|
||||||
# is equal to the width*height of the max resolution of the gpu multiplied
|
|
||||||
# by the "vramSize" for that tier. For example, a T2 gpu can have 80*25*2 of
|
|
||||||
# text buffer space allocated
|
|
||||||
vramSizes: [
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3
|
|
||||||
]
|
|
||||||
|
|
||||||
# This setting allows you to fine-tune how RAM sizes are scaled internally
|
# This setting allows you to fine-tune how RAM sizes are scaled internally
|
||||||
# on 64 Bit machines (i.e. when the Minecraft server runs in a 64 Bit VM).
|
# on 64 Bit machines (i.e. when the Minecraft server runs in a 64 Bit VM).
|
||||||
# Why is this even necessary? Because objects consume more memory in a 64
|
# Why is this even necessary? Because objects consume more memory in a 64
|
||||||
@ -1596,4 +1586,20 @@ opencomputers {
|
|||||||
# whitelist and the blacklist, the blacklist will win.
|
# whitelist and the blacklist, the blacklist will win.
|
||||||
dimWhitelist: []
|
dimWhitelist: []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Graphics Card Component Settings
|
||||||
|
gpu {
|
||||||
|
# Video ram can be allocated on a gpu. The amount of vram you can allocate
|
||||||
|
# is equal to the width*height of the max resolution of the gpu multiplied
|
||||||
|
# by the "vramSize" for that tier. For example, a T2 gpu can have 80*25*2 of
|
||||||
|
# text buffer space allocated
|
||||||
|
vramSizes: [ 1, 2, 3 ]
|
||||||
|
|
||||||
|
# This setting assigns the budget call cost to invoke bitblt to write vram
|
||||||
|
# to a screen. Video ram can bitblit to a screen which can cause real life
|
||||||
|
# network laod the defaults settings put bitblit network impact close to gpu.set
|
||||||
|
# Increase these values to throttle bitblt more. The cost tier N is bitbltCost * 2^(tier)
|
||||||
|
# default is .5, which gives: .5, 1, 4
|
||||||
|
bitbltCost: 0.5
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,6 +228,7 @@ oc:gui.Rack.None=None
|
|||||||
oc:gui.Rack.Right=Right
|
oc:gui.Rack.Right=Right
|
||||||
oc:gui.Rack.Enabled=Enabled
|
oc:gui.Rack.Enabled=Enabled
|
||||||
oc:gui.Rack.Disabled=Disabled
|
oc:gui.Rack.Disabled=Disabled
|
||||||
|
oc:gui.Rack.RelayModeTooltip=Relay Mode
|
||||||
oc:gui.Rack.Top=Top
|
oc:gui.Rack.Top=Top
|
||||||
oc:gui.Switch.PacketsPerCycle=Packets / cycle
|
oc:gui.Switch.PacketsPerCycle=Packets / cycle
|
||||||
oc:gui.Switch.QueueSize=Queue size
|
oc:gui.Switch.QueueSize=Queue size
|
||||||
@ -380,6 +381,7 @@ oc:tooltip.upgradesolargenerator=Can be used to generate energy from sunlight on
|
|||||||
oc:tooltip.upgradetank=This upgrade provides a tank for fluid storage for robots and drones. Without one of these, they will not be able to store fluids internally.
|
oc:tooltip.upgradetank=This upgrade provides a tank for fluid storage for robots and drones. Without one of these, they will not be able to store fluids internally.
|
||||||
oc:tooltip.upgradetankcontroller=This upgrade allows robots and drones more control in how they interact with external tanks, and allows them to transfer fluids into and out of fluid tank items in their inventory.
|
oc:tooltip.upgradetankcontroller=This upgrade allows robots and drones more control in how they interact with external tanks, and allows them to transfer fluids into and out of fluid tank items in their inventory.
|
||||||
oc:tooltip.upgradetractorbeam=Equips a device with extremely advanced technology, nicknamed the "Item Magnet". Allows the device to pick up items anywhere within 3 blocks of its location.
|
oc:tooltip.upgradetractorbeam=Equips a device with extremely advanced technology, nicknamed the "Item Magnet". Allows the device to pick up items anywhere within 3 blocks of its location.
|
||||||
|
oc:tooltip.upgradetrading=Allows robots and drones to trade with villagers.
|
||||||
oc:tooltip.waypoint=Provides a point of reference to devices with a navigation upgrade.
|
oc:tooltip.waypoint=Provides a point of reference to devices with a navigation upgrade.
|
||||||
oc:tooltip.wirelessnetworkcard=Allows wireless sending of network messages in addition to normal ones. You can adjust the §fsignal strength§7 to control how far messages are sent. Higher signal strength results in higher energy consumption.
|
oc:tooltip.wirelessnetworkcard=Allows wireless sending of network messages in addition to normal ones. You can adjust the §fsignal strength§7 to control how far messages are sent. Higher signal strength results in higher energy consumption.
|
||||||
oc:tooltip.worldsensorcard=Allows reading out information about the world, such as its gravity and whether it has a breathable atmosphere. Use results at own risk. The manufacturer takes no responsibility for bodily or material harm caused by decisions made upon the cards' outputs. We have lawyers. And money. Don't even try.
|
oc:tooltip.worldsensorcard=Allows reading out information about the world, such as its gravity and whether it has a breathable atmosphere. Use results at own risk. The manufacturer takes no responsibility for bodily or material harm caused by decisions made upon the cards' outputs. We have lawyers. And money. Don't even try.
|
||||||
|
@ -1 +1 @@
|
|||||||
{label = "OpenOS", reboot=true, setlabel=true, setboot=true}
|
{label = "OpenOS", reboot=true, setlabel=true, setboot=true, noclobber={"etc/rc.cfg","home/.shrc"}}
|
||||||
|
@ -30,7 +30,7 @@ options =
|
|||||||
P = options.P,
|
P = options.P,
|
||||||
v = options.v,
|
v = options.v,
|
||||||
x = options.x,
|
x = options.x,
|
||||||
skip = options.skip,
|
skip = {options.skip},
|
||||||
}
|
}
|
||||||
|
|
||||||
return transfer.batch(args, options)
|
return transfer.batch(args, options)
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
local computer = require("computer")
|
local computer = require("computer")
|
||||||
local shell = require("shell")
|
|
||||||
|
|
||||||
local options
|
local options
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -12,21 +10,23 @@ do
|
|||||||
options = basic(...)
|
options = basic(...)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not options then return end
|
if not options then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if computer.freeMemory() < 50000 then
|
if computer.freeMemory() < 50000 then
|
||||||
print("Low memory, collecting garbage")
|
print("Low memory, collecting garbage")
|
||||||
for i=1,20 do os.sleep(0) end
|
for i = 1, 20 do
|
||||||
|
os.sleep(0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local cp, reason = loadfile(shell.resolve("cp", "lua"), "bt", _G)
|
local transfer = require("tools/transfer")
|
||||||
assert(cp, reason)
|
for _, inst in ipairs(options.cp_args) do
|
||||||
|
local ec = transfer.batch(table.unpack(inst))
|
||||||
local ok, ec = pcall(cp, table.unpack(options.cp_args))
|
if ec ~= nil and ec ~= 0 then
|
||||||
assert(ok, ec)
|
return ec
|
||||||
|
end
|
||||||
if ec ~= nil and ec ~= 0 then
|
|
||||||
return ec
|
|
||||||
end
|
end
|
||||||
|
|
||||||
print("Installation complete!")
|
print("Installation complete!")
|
||||||
@ -44,7 +44,7 @@ end
|
|||||||
|
|
||||||
if options.reboot then
|
if options.reboot then
|
||||||
io.write("Reboot now? [Y/n] ")
|
io.write("Reboot now? [Y/n] ")
|
||||||
if ((io.read() or "n").."y"):match("^%s*[Yy]") then
|
if ((io.read() or "n") .. "y"):match("^%s*[Yy]") then
|
||||||
print("\nRebooting now!\n")
|
print("\nRebooting now!\n")
|
||||||
computer.shutdown(true)
|
computer.shutdown(true)
|
||||||
end
|
end
|
||||||
|
@ -24,7 +24,7 @@ options =
|
|||||||
i = options.i,
|
i = options.i,
|
||||||
v = options.v,
|
v = options.v,
|
||||||
n = options.n, -- no clobber
|
n = options.n, -- no clobber
|
||||||
skip = options.skip,
|
skip = {options.skip},
|
||||||
P = true, -- move operations always preserve
|
P = true, -- move operations always preserve
|
||||||
r = true, -- move is allowed to move entire dirs
|
r = true, -- move is allowed to move entire dirs
|
||||||
x = true, -- cannot move mount points
|
x = true, -- cannot move mount points
|
||||||
|
@ -32,3 +32,7 @@ for _,line in ipairs(lines) do
|
|||||||
io.write(borders[2][1], " ", line, (" "):rep(maxLine - #line + 1), borders[2][3], " \n")
|
io.write(borders[2][1], " ", line, (" "):rep(maxLine - #line + 1), borders[2][3], " \n")
|
||||||
end
|
end
|
||||||
io.write(borders[3][1] .. string.rep(borders[3][2], maxLine + 2) .. borders[3][3] .. "\n")
|
io.write(borders[3][1] .. string.rep(borders[3][2], maxLine + 2) .. borders[3][3] .. "\n")
|
||||||
|
|
||||||
|
if require("filesystem").get("home").isReadOnly() then
|
||||||
|
io.write("\27[33mNote: Your home directory is readonly. Run `install` and reboot.\27[m\n")
|
||||||
|
end
|
||||||
|
@ -20,7 +20,6 @@ shell.setAlias("cls", "clear")
|
|||||||
shell.setAlias("rs", "redstone")
|
shell.setAlias("rs", "redstone")
|
||||||
shell.setAlias("view", "edit -r")
|
shell.setAlias("view", "edit -r")
|
||||||
shell.setAlias("help", "man")
|
shell.setAlias("help", "man")
|
||||||
shell.setAlias("cp", "cp -i")
|
|
||||||
shell.setAlias("l", "ls -lhp")
|
shell.setAlias("l", "ls -lhp")
|
||||||
shell.setAlias("..", "cd ..")
|
shell.setAlias("..", "cd ..")
|
||||||
shell.setAlias("df", "df -h")
|
shell.setAlias("df", "df -h")
|
||||||
|
@ -27,7 +27,7 @@ local utils
|
|||||||
|
|
||||||
local rootfs = fs.get("/")
|
local rootfs = fs.get("/")
|
||||||
if not rootfs then
|
if not rootfs then
|
||||||
io.stderr:write("no root filesystem, aborting\n");
|
io.stderr:write("no root filesystem, aborting\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -86,11 +86,13 @@ for dev, path in pairs(devices) do
|
|||||||
io.stderr:write("Cannot install to " .. options.to .. ", it is read only\n")
|
io.stderr:write("Cannot install to " .. options.to .. ", it is read only\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
elseif specified or
|
elseif
|
||||||
not (source_filter and address:find(source_filter, 1, true) == 1) and -- specified for source
|
specified or
|
||||||
not target_filter and
|
not (source_filter and address:find(source_filter, 1, true) == 1) and -- specified for source
|
||||||
address ~= tmpAddress then
|
not target_filter and
|
||||||
table.insert(targets, {dev=dev, path=install_path, specified=specified})
|
address ~= tmpAddress
|
||||||
|
then
|
||||||
|
table.insert(targets, {dev = dev, path = install_path, specified = specified})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -105,11 +107,11 @@ for dev, path in pairs(devices) do
|
|||||||
local install_path = dev == source_filter_dev and options.from or path
|
local install_path = dev == source_filter_dev and options.from or path
|
||||||
local specified = source_filter and address:find(source_filter, 1, true) == 1
|
local specified = source_filter and address:find(source_filter, 1, true) == 1
|
||||||
|
|
||||||
if fs.list(install_path)()
|
if
|
||||||
and (specified or
|
fs.list(install_path)() and
|
||||||
not source_filter and
|
(specified or
|
||||||
address ~= tmpAddress and
|
not source_filter and address ~= tmpAddress and not (address == rootfs.address and not rootfs.isReadOnly()))
|
||||||
not (address == rootfs.address and not rootfs.isReadOnly())) then
|
then
|
||||||
local prop = {}
|
local prop = {}
|
||||||
local prop_path = install_path .. "/.prop"
|
local prop_path = install_path .. "/.prop"
|
||||||
local prop_file = fs.open(prop_path)
|
local prop_file = fs.open(prop_path)
|
||||||
@ -125,7 +127,7 @@ for dev, path in pairs(devices) do
|
|||||||
end
|
end
|
||||||
if not prop.ignore then
|
if not prop.ignore then
|
||||||
if not label or label:lower() == (prop.label or dev.getLabel() or ""):lower() then
|
if not label or label:lower() == (prop.label or dev.getLabel() or ""):lower() then
|
||||||
table.insert(sources, {dev=dev, path=install_path, prop=prop, specified=specified})
|
table.insert(sources, {dev = dev, path = install_path, prop = prop, specified = specified})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -137,23 +139,24 @@ if #sources ~= 1 then
|
|||||||
utils = loadfile(utils_path, "bt", _G)
|
utils = loadfile(utils_path, "bt", _G)
|
||||||
source = utils("select", "sources", options, sources)
|
source = utils("select", "sources", options, sources)
|
||||||
end
|
end
|
||||||
if not source then return end
|
if not source then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
options =
|
options = {
|
||||||
{
|
from = source.path .. "/",
|
||||||
from = source.path .. '/',
|
fromDir = fs.canonical(options.fromDir or source.prop.fromDir or ""),
|
||||||
fromDir = fs.canonical(options.fromDir or source.prop.fromDir or ""),
|
root = fs.canonical(options.root or options.toDir or source.prop.root or ""),
|
||||||
root = fs.canonical(options.root or options.toDir or source.prop.root or ""),
|
update = options.update or options.u,
|
||||||
update = options.update or options.u,
|
label = source.prop.label or label,
|
||||||
label = source.prop.label or label,
|
|
||||||
setlabel = not (options.nosetlabel or options.nolabelset) and source.prop.setlabel,
|
setlabel = not (options.nosetlabel or options.nolabelset) and source.prop.setlabel,
|
||||||
setboot = not (options.nosetboot or options.noboot) and source.prop.setboot,
|
setboot = not (options.nosetboot or options.noboot) and source.prop.setboot,
|
||||||
reboot = not options.noreboot and source.prop.reboot,
|
reboot = not options.noreboot and source.prop.reboot
|
||||||
}
|
}
|
||||||
local source_display = options.label or source.dev.getLabel() or source.path
|
local source_display = options.label or source.dev.getLabel() or source.path
|
||||||
|
|
||||||
-- Remove the source from the target options
|
-- Remove the source from the target options
|
||||||
for index,entry in ipairs(targets) do
|
for index, entry in ipairs(targets) do
|
||||||
if entry.dev == source.dev then
|
if entry.dev == source.dev then
|
||||||
table.remove(targets, index)
|
table.remove(targets, index)
|
||||||
target = targets[1]
|
target = targets[1]
|
||||||
@ -162,47 +165,67 @@ end
|
|||||||
|
|
||||||
-- Ask the user to select a target
|
-- Ask the user to select a target
|
||||||
if #targets ~= 1 then
|
if #targets ~= 1 then
|
||||||
if #sources == 1 then
|
if #sources == 1 then
|
||||||
io.write(source_display, " selected for install\n")
|
io.write(source_display, " selected for install\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
utils = utils or loadfile(utils_path, "bt", _G)
|
utils = utils or loadfile(utils_path, "bt", _G)
|
||||||
target = utils("select", "targets", options, targets)
|
target = utils("select", "targets", options, targets)
|
||||||
end
|
end
|
||||||
if not target then return end
|
if not target then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
options.to = target.path .. '/'
|
options.to = target.path .. "/"
|
||||||
|
|
||||||
local cp_args =
|
local function resolveFrom(path)
|
||||||
{
|
return fs.concat(options.from, options.fromDir) .. "/" .. path
|
||||||
"-vrx" .. (options.update and "ui" or ""),
|
end
|
||||||
"--skip=.prop",
|
|
||||||
fs.concat(options.from, options.fromDir) .. "/.",
|
local fullTargetPath = fs.concat(options.to, options.root)
|
||||||
fs.concat(options.to , options.root)
|
local transfer_args = {
|
||||||
|
{
|
||||||
|
{resolveFrom("."), fullTargetPath},
|
||||||
|
{
|
||||||
|
cmd = "cp",
|
||||||
|
r = true, v = true, x = true, u = options.update, i = options.update,
|
||||||
|
skip = {resolveFrom(".prop")},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if source.prop.noclobber and #source.prop.noclobber > 0 then
|
||||||
|
local noclobber_opts = {cmd = "cp", v = true, n = true}
|
||||||
|
for _, noclobber in ipairs(source.prop.noclobber or {}) do
|
||||||
|
local noclobberFrom = resolveFrom(noclobber)
|
||||||
|
local noclobberTo = fs.concat(fullTargetPath, noclobber)
|
||||||
|
table.insert(transfer_args[1][2].skip, noclobberFrom)
|
||||||
|
table.insert(transfer_args, {{noclobberFrom, noclobberTo}, noclobber_opts})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local special_target = ""
|
local special_target = ""
|
||||||
if #targets > 1 or target_filter or source_filter then
|
if #targets > 1 or target_filter or source_filter then
|
||||||
special_target = " to " .. cp_args[4]
|
special_target = " to " .. transfer_args[1][1][2]
|
||||||
end
|
end
|
||||||
|
|
||||||
io.write("Install " .. source_display .. special_target .. "? [Y/n] ")
|
io.write("Install " .. source_display .. special_target .. "? [Y/n] ")
|
||||||
if not ((io.read() or "n").."y"):match("^%s*[Yy]") then
|
if not ((io.read() or "n") .. "y"):match("^%s*[Yy]") then
|
||||||
io.write("Installation cancelled\n")
|
io.write("Installation cancelled\n")
|
||||||
os.exit()
|
os.exit()
|
||||||
end
|
end
|
||||||
|
|
||||||
local installer_path = options.from .. "/.install"
|
local installer_path = options.from .. "/.install"
|
||||||
if fs.exists(installer_path) then
|
if fs.exists(installer_path) then
|
||||||
local installer, reason = loadfile(installer_path, "bt", setmetatable({install=options}, {__index = _G}))
|
local installer, reason = loadfile(installer_path, "bt", setmetatable({install = options}, {__index = _G}))
|
||||||
if not installer then
|
if not installer then
|
||||||
io.stderr:write("installer failed to load: " .. tostring(reason) .. '\n')
|
io.stderr:write("installer failed to load: " .. tostring(reason) .. "\n")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
end
|
end
|
||||||
os.exit(installer())
|
os.exit(installer())
|
||||||
end
|
end
|
||||||
|
|
||||||
options.cp_args = cp_args
|
options.cp_args = transfer_args
|
||||||
options.target = target
|
options.target = target
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
@ -116,15 +116,12 @@ while term.isAvailable() do
|
|||||||
else
|
else
|
||||||
local ok, why = pcall(function()
|
local ok, why = pcall(function()
|
||||||
for i = 2, result.n do
|
for i = 2, result.n do
|
||||||
io.write(require("serialization").serialize(result[i], true) .. "\t")
|
io.write(require("serialization").serialize(result[i], true), i < result.n and "\t" or "\n")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
if not ok then
|
if not ok then
|
||||||
io.stderr:write("crashed serializing result: ", tostring(why))
|
io.stderr:write("crashed serializing result: ", tostring(why))
|
||||||
end
|
end
|
||||||
if term.getCursor() > 1 then
|
|
||||||
io.write("\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
io.stderr:write(tostring(reason) .. "\n")
|
io.stderr:write(tostring(reason) .. "\n")
|
||||||
|
@ -93,7 +93,7 @@ function lib.recurse(fromPath, toPath, options, origin, top)
|
|||||||
local toPathFull = shell.resolve(toPath)
|
local toPathFull = shell.resolve(toPath)
|
||||||
local mv = options.cmd == "mv"
|
local mv = options.cmd == "mv"
|
||||||
local verbose = options.v and (not mv or top)
|
local verbose = options.v and (not mv or top)
|
||||||
if select(2, fromPathFull:find(options.skip)) == #fromPathFull then
|
if options.skip[fromPathFull] then
|
||||||
status(verbose, string.format("skipping %s", fromPath))
|
status(verbose, string.format("skipping %s", fromPath))
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -221,8 +221,13 @@ function lib.batch(args, options)
|
|||||||
-- standardized options
|
-- standardized options
|
||||||
options.i = options.i and not options.f
|
options.i = options.i and not options.f
|
||||||
options.P = options.P or options.r
|
options.P = options.P or options.r
|
||||||
options.skip = text.escapeMagic(options.skip or "")
|
|
||||||
|
local skips = options.skip or {}
|
||||||
|
options.skip = {}
|
||||||
|
for _, skip_item in ipairs(skips) do
|
||||||
|
options.skip[shell.resolve(skip_item)] = true
|
||||||
|
end
|
||||||
|
|
||||||
local origin = {}
|
local origin = {}
|
||||||
for dev,path in fs.mounts() do
|
for dev,path in fs.mounts() do
|
||||||
origin[path] = dev
|
origin[path] = dev
|
||||||
|
@ -796,7 +796,7 @@ sandbox = {
|
|||||||
local handled = false
|
local handled = false
|
||||||
checkArg(2, msgh, "function")
|
checkArg(2, msgh, "function")
|
||||||
local result = table.pack(xpcall(f, function(...)
|
local result = table.pack(xpcall(f, function(...)
|
||||||
if (...) == tooLongWithoutYielding then
|
if rawequal((...), tooLongWithoutYielding) then
|
||||||
return tooLongWithoutYielding
|
return tooLongWithoutYielding
|
||||||
elseif handled then
|
elseif handled then
|
||||||
return ...
|
return ...
|
||||||
@ -805,7 +805,7 @@ sandbox = {
|
|||||||
return msgh(...)
|
return msgh(...)
|
||||||
end
|
end
|
||||||
end, ...))
|
end, ...))
|
||||||
if result[2] == tooLongWithoutYielding then
|
if rawequal(result[2], tooLongWithoutYielding) then
|
||||||
result = table.pack(result[1], select(2, pcallTimeoutCheck(pcall(msgh, tostring(tooLongWithoutYielding)))))
|
result = table.pack(result[1], select(2, pcallTimeoutCheck(pcall(msgh, tostring(tooLongWithoutYielding)))))
|
||||||
end
|
end
|
||||||
return table.unpack(result, 1, result.n)
|
return table.unpack(result, 1, result.n)
|
||||||
|
@ -121,6 +121,7 @@ Rinzler # Tron
|
|||||||
Twiki # Buck Rodgers
|
Twiki # Buck Rodgers
|
||||||
Uniblab # The Jetsons
|
Uniblab # The Jetsons
|
||||||
Unimate # First programmable robot.
|
Unimate # First programmable robot.
|
||||||
|
VEGA # Doom 2016
|
||||||
Vertigo # Perry Rhodan
|
Vertigo # Perry Rhodan
|
||||||
Vexatos # Contributor
|
Vexatos # Contributor
|
||||||
V.I.K.I. # Virtual Interactive Kinetic Intelligence - I, Robot
|
V.I.K.I. # Virtual Interactive Kinetic Intelligence - I, Robot
|
||||||
|
@ -143,6 +143,8 @@ object Localization {
|
|||||||
def RelayEnabled: String = localizeImmediately("gui.Rack.Enabled")
|
def RelayEnabled: String = localizeImmediately("gui.Rack.Enabled")
|
||||||
|
|
||||||
def RelayDisabled: String = localizeImmediately("gui.Rack.Disabled")
|
def RelayDisabled: String = localizeImmediately("gui.Rack.Disabled")
|
||||||
|
|
||||||
|
def RelayModeTooltip: String = localizeImmediately("gui.Rack.RelayModeTooltip")
|
||||||
}
|
}
|
||||||
|
|
||||||
object Switch {
|
object Switch {
|
||||||
|
@ -92,12 +92,6 @@ class Settings(val config: Config) {
|
|||||||
OpenComputers.log.warn("Bad number of RAM sizes, ignoring.")
|
OpenComputers.log.warn("Bad number of RAM sizes, ignoring.")
|
||||||
Array(192, 256, 384, 512, 768, 1024)
|
Array(192, 256, 384, 512, 768, 1024)
|
||||||
}
|
}
|
||||||
val vramSizes = Array(config.getIntList("computer.lua.vramSizes"): _*) match {
|
|
||||||
case Array(tier1, tier2, tier3) => Array(tier1: Int, tier2: Int, tier3: Int)
|
|
||||||
case _ =>
|
|
||||||
OpenComputers.log.warn("Bad number of VRAM sizes, ignoring.")
|
|
||||||
Array(1, 2, 3)
|
|
||||||
}
|
|
||||||
val ramScaleFor64Bit = config.getDouble("computer.lua.ramScaleFor64Bit") max 1
|
val ramScaleFor64Bit = config.getDouble("computer.lua.ramScaleFor64Bit") max 1
|
||||||
val maxTotalRam = config.getInt("computer.lua.maxTotalRam") max 0
|
val maxTotalRam = config.getInt("computer.lua.maxTotalRam") max 0
|
||||||
|
|
||||||
@ -476,24 +470,34 @@ class Settings(val config: Config) {
|
|||||||
|
|
||||||
// >= 1.7.4
|
// >= 1.7.4
|
||||||
val maxSignalQueueSize: Int = (if (config.hasPath("computer.maxSignalQueueSize")) config.getInt("computer.maxSignalQueueSize") else 256) min 256
|
val maxSignalQueueSize: Int = (if (config.hasPath("computer.maxSignalQueueSize")) config.getInt("computer.maxSignalQueueSize") else 256) min 256
|
||||||
|
|
||||||
|
// >= 1.7.6
|
||||||
|
val vramSizes: Array[Double] = Array(config.getDoubleList("gpu.vramSizes"): _*) match {
|
||||||
|
case Array(tier1, tier2, tier3) => Array(tier1: Double, tier2: Double, tier3: Double)
|
||||||
|
case _ =>
|
||||||
|
OpenComputers.log.warn("Bad number of VRAM sizes (expected 3), ignoring.")
|
||||||
|
Array(1, 2, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
val bitbltCost: Double = if (config.hasPath("gpu.bitbltCost")) config.getDouble("gpu.bitbltCost") else 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
object Settings {
|
object Settings {
|
||||||
val resourceDomain = "opencomputers"
|
val resourceDomain = "opencomputers"
|
||||||
val namespace = "oc:"
|
val namespace = "oc:"
|
||||||
val savePath = "opencomputers/"
|
val savePath = "opencomputers/"
|
||||||
val scriptPath = "/assets/" + resourceDomain + "/lua/"
|
val scriptPath: String = "/assets/" + resourceDomain + "/lua/"
|
||||||
val screenResolutionsByTier = Array((50, 16), (80, 25), (160, 50))
|
val screenResolutionsByTier: Array[(Int, Int)] = Array((50, 16), (80, 25), (160, 50))
|
||||||
val screenDepthsByTier = Array(api.internal.TextBuffer.ColorDepth.OneBit, api.internal.TextBuffer.ColorDepth.FourBit, api.internal.TextBuffer.ColorDepth.EightBit)
|
val screenDepthsByTier: Array[api.internal.TextBuffer.ColorDepth] = Array(api.internal.TextBuffer.ColorDepth.OneBit, api.internal.TextBuffer.ColorDepth.FourBit, api.internal.TextBuffer.ColorDepth.EightBit)
|
||||||
val deviceComplexityByTier = Array(12, 24, 32, 9001)
|
val deviceComplexityByTier: Array[Int] = Array(12, 24, 32, 9001)
|
||||||
var rTreeDebugRenderer = false
|
var rTreeDebugRenderer = false
|
||||||
var blockRenderId = -1
|
var blockRenderId: Int = -1
|
||||||
|
|
||||||
def basicScreenPixels = screenResolutionsByTier(0)._1 * screenResolutionsByTier(0)._2
|
def basicScreenPixels: Int = screenResolutionsByTier(0)._1 * screenResolutionsByTier(0)._2
|
||||||
|
|
||||||
private var settings: Settings = _
|
private var settings: Settings = _
|
||||||
|
|
||||||
def get = settings
|
def get: Settings = settings
|
||||||
|
|
||||||
def load(file: File) = {
|
def load(file: File) = {
|
||||||
import scala.compat.Platform.EOL
|
import scala.compat.Platform.EOL
|
||||||
|
@ -733,13 +733,11 @@ object PacketHandler extends CommonPacketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def onTextBufferRamInit(p: PacketParser, buffer: api.internal.TextBuffer): Unit = {
|
def onTextBufferRamInit(p: PacketParser, buffer: api.internal.TextBuffer): Unit = {
|
||||||
|
val owner = p.readUTF()
|
||||||
val id = p.readInt()
|
val id = p.readInt()
|
||||||
val nbt = p.readNBT()
|
val nbt = p.readNBT()
|
||||||
|
|
||||||
buffer match {
|
component.ClientGpuTextBufferHandler.loadBuffer(buffer, owner, id, nbt)
|
||||||
case screen: component.traits.VideoRamAware => screen.loadBuffer(id, nbt)
|
|
||||||
case _ => // ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def onTextBufferBitBlt(p: PacketParser, buffer: api.internal.TextBuffer): Unit = {
|
def onTextBufferBitBlt(p: PacketParser, buffer: api.internal.TextBuffer): Unit = {
|
||||||
@ -747,24 +745,19 @@ object PacketHandler extends CommonPacketHandler {
|
|||||||
val row = p.readInt()
|
val row = p.readInt()
|
||||||
val w = p.readInt()
|
val w = p.readInt()
|
||||||
val h = p.readInt()
|
val h = p.readInt()
|
||||||
|
val owner = p.readUTF()
|
||||||
val id = p.readInt()
|
val id = p.readInt()
|
||||||
val fromCol = p.readInt()
|
val fromCol = p.readInt()
|
||||||
val fromRow = p.readInt()
|
val fromRow = p.readInt()
|
||||||
|
|
||||||
component.GpuTextBuffer.bitblt(buffer, col, row, w, h, id, fromCol, fromRow)
|
component.ClientGpuTextBufferHandler.bitblt(buffer, col, row, w, h, owner, id, fromCol, fromRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
def onTextBufferRamDestroy(p: PacketParser, buffer: api.internal.TextBuffer): Unit = {
|
def onTextBufferRamDestroy(p: PacketParser, buffer: api.internal.TextBuffer): Unit = {
|
||||||
val length = p.readInt()
|
val owner = p.readUTF()
|
||||||
val ids = new Array[Int](length)
|
val id = p.readInt()
|
||||||
for (i <- 0 until length) {
|
|
||||||
ids(i) = p.readInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer match {
|
component.ClientGpuTextBufferHandler.removeBuffer(buffer, owner, id)
|
||||||
case screen: component.traits.VideoRamAware => screen.removeBuffers(ids)
|
|
||||||
case _ => // ignore, not compatible with bitblts
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def onTextBufferMultiRawSetText(p: PacketParser, buffer: api.internal.TextBuffer) {
|
def onTextBufferMultiRawSetText(p: PacketParser, buffer: api.internal.TextBuffer) {
|
||||||
|
@ -14,6 +14,8 @@ import net.minecraft.entity.player.InventoryPlayer
|
|||||||
import net.minecraft.util.EnumFacing
|
import net.minecraft.util.EnumFacing
|
||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
|
|
||||||
|
import scala.collection.convert.WrapAsJava.asJavaCollection
|
||||||
|
|
||||||
class Rack(playerInventory: InventoryPlayer, val rack: tileentity.Rack) extends DynamicGuiContainer(new container.Rack(playerInventory, rack)) {
|
class Rack(playerInventory: InventoryPlayer, val rack: tileentity.Rack) extends DynamicGuiContainer(new container.Rack(playerInventory, rack)) {
|
||||||
ySize = 210
|
ySize = 210
|
||||||
|
|
||||||
@ -251,6 +253,12 @@ class Rack(playerInventory: InventoryPlayer, val rack: tileentity.Rack) extends
|
|||||||
x, y, 0x404040)
|
x, y, 0x404040)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (relayButton.isMouseOver) {
|
||||||
|
val tooltip = new java.util.ArrayList[String]
|
||||||
|
tooltip.addAll(asJavaCollection(Localization.Rack.RelayModeTooltip.lines.toIterable))
|
||||||
|
copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRenderer)
|
||||||
|
}
|
||||||
|
|
||||||
RenderState.popAttrib()
|
RenderState.popAttrib()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
package li.cil.oc.common.component
|
package li.cil.oc.common.component
|
||||||
|
|
||||||
import li.cil.oc.api.network.{ManagedEnvironment, Message, Node}
|
import java.io.InvalidObjectException
|
||||||
|
import java.security.InvalidParameterException
|
||||||
|
|
||||||
|
import li.cil.oc.api.network.{Environment, Message, Node}
|
||||||
import net.minecraft.entity.player.EntityPlayer
|
import net.minecraft.entity.player.EntityPlayer
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
import li.cil.oc.api.internal.TextBuffer.ColorDepth
|
import li.cil.oc.api.internal.TextBuffer.ColorDepth
|
||||||
import li.cil.oc.api
|
import li.cil.oc.api
|
||||||
import li.cil.oc.common.component.traits.TextBufferProxy
|
import li.cil.oc.common.component.traits.{TextBufferProxy, VideoRamDevice, VideoRamRasterizer}
|
||||||
import li.cil.oc.util.PackedColor
|
|
||||||
|
class GpuTextBuffer(val owner: String, val id: Int, val data: li.cil.oc.util.TextBuffer) extends traits.TextBufferProxy {
|
||||||
|
|
||||||
|
// the gpu ram does not join nor is searchable to the network
|
||||||
|
// this field is required because the api TextBuffer is an Environment
|
||||||
|
override def node(): Node = {
|
||||||
|
throw new InvalidObjectException("GpuTextBuffers do not have nodes")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GpuTextBuffer(val id: Int, val data: li.cil.oc.util.TextBuffer) extends ManagedEnvironment with traits.TextBufferProxy {
|
|
||||||
override def getMaximumWidth: Int = data.width
|
override def getMaximumWidth: Int = data.width
|
||||||
override def getMaximumHeight: Int = data.height
|
override def getMaximumHeight: Int = data.height
|
||||||
override def getViewportWidth: Int = data.height
|
override def getViewportWidth: Int = data.height
|
||||||
@ -17,10 +27,19 @@ class GpuTextBuffer(val id: Int, val data: li.cil.oc.util.TextBuffer) extends Ma
|
|||||||
var dirty: Boolean = true
|
var dirty: Boolean = true
|
||||||
override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean): Unit = dirty = true
|
override def onBufferSet(col: Int, row: Int, s: String, vertical: Boolean): Unit = dirty = true
|
||||||
override def onBufferColorChange(): Unit = dirty = true
|
override def onBufferColorChange(): Unit = dirty = true
|
||||||
override def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, id: Int, fromCol: Int, fromRow: Int): Unit = dirty = true
|
|
||||||
override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int): Unit = dirty = true
|
override def onBufferCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int): Unit = dirty = true
|
||||||
override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char): Unit = dirty = true
|
override def onBufferFill(col: Int, row: Int, w: Int, h: Int, c: Char): Unit = dirty = true
|
||||||
override def onBufferRamInit(id: Int, ram: TextBufferProxy): Unit = dirty = false
|
|
||||||
|
override def load(nbt: NBTTagCompound): Unit = {
|
||||||
|
// the data is initially dirty because other devices don't know about it yet
|
||||||
|
data.load(nbt)
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override def save(nbt: NBTTagCompound): Unit = {
|
||||||
|
data.save(nbt)
|
||||||
|
dirty = false
|
||||||
|
}
|
||||||
|
|
||||||
override def setEnergyCostPerTick(value: Double): Unit = {}
|
override def setEnergyCostPerTick(value: Double): Unit = {}
|
||||||
override def getEnergyCostPerTick: Double = 0
|
override def getEnergyCostPerTick: Double = 0
|
||||||
@ -47,29 +66,42 @@ class GpuTextBuffer(val id: Int, val data: li.cil.oc.util.TextBuffer) extends Ma
|
|||||||
override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit = {}
|
override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit = {}
|
||||||
override def canUpdate: Boolean = false
|
override def canUpdate: Boolean = false
|
||||||
override def update(): Unit = {}
|
override def update(): Unit = {}
|
||||||
override def node: li.cil.oc.api.network.Node = null
|
|
||||||
override def onConnect(node: Node): Unit = {}
|
override def onConnect(node: Node): Unit = {}
|
||||||
override def onDisconnect(node: Node): Unit = {}
|
override def onDisconnect(node: Node): Unit = {}
|
||||||
override def onMessage(message: Message): Unit = {}
|
override def onMessage(message: Message): Unit = {}
|
||||||
override def load(nbt: NBTTagCompound): Unit = {}
|
|
||||||
override def save(nbt: NBTTagCompound): Unit = {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object GpuTextBuffer {
|
object ClientGpuTextBufferHandler {
|
||||||
def wrap(id: Int, data: li.cil.oc.util.TextBuffer): GpuTextBuffer = new GpuTextBuffer(id, data)
|
def bitblt(dst: api.internal.TextBuffer, col: Int, row: Int, w: Int, h: Int, owner: String, srcId: Int, fromCol: Int, fromRow: Int): Unit = {
|
||||||
|
|
||||||
def bitblt(dst: api.internal.TextBuffer, col: Int, row: Int, w: Int, h: Int, srcId: Int, fromCol: Int, fromRow: Int): Unit = {
|
|
||||||
dst match {
|
dst match {
|
||||||
case screen: traits.TextBufferProxy => screen.getBuffer(srcId) match {
|
case videoDevice: VideoRamRasterizer => videoDevice.getBuffer(owner, srcId) match {
|
||||||
case Some(buffer: GpuTextBuffer) => {
|
case Some(buffer: GpuTextBuffer) => {
|
||||||
bitblt(dst, col, row, w, h, buffer, fromCol, fromRow)
|
GpuTextBuffer.bitblt(dst, col, row, w, h, buffer, fromCol, fromRow)
|
||||||
}
|
}
|
||||||
case _ => // ignore - got a bitblt for a missing buffer
|
case _ => // ignore - got a bitblt for a missing buffer
|
||||||
}
|
}
|
||||||
case _ => // ignore - weird packet handler called this, should only happen for screens that know about thsi
|
case _ => // ignore - weird packet handler called this, should only happen for video ram aware devices
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def removeBuffer(buffer: api.internal.TextBuffer, owner: String, id: Int): Boolean = {
|
||||||
|
buffer match {
|
||||||
|
case screen: VideoRamRasterizer => screen.removeBuffer(owner, id)
|
||||||
|
case _ => false // ignore, not compatible with bitblts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def loadBuffer(buffer: api.internal.TextBuffer, owner: String, id: Int, nbt: NBTTagCompound): Boolean = {
|
||||||
|
buffer match {
|
||||||
|
case screen: VideoRamRasterizer => screen.loadBuffer(owner, id, nbt)
|
||||||
|
case _ => false // ignore, not compatible with bitblts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object GpuTextBuffer {
|
||||||
|
def wrap(owner: String, id: Int, data: li.cil.oc.util.TextBuffer): GpuTextBuffer = new GpuTextBuffer(owner, id, data)
|
||||||
|
|
||||||
def bitblt(dst: api.internal.TextBuffer, col: Int, row: Int, w: Int, h: Int, src: api.internal.TextBuffer, fromCol: Int, fromRow: Int): Unit = {
|
def bitblt(dst: api.internal.TextBuffer, col: Int, row: Int, w: Int, h: Int, src: api.internal.TextBuffer, fromCol: Int, fromRow: Int): Unit = {
|
||||||
val x = col - 1
|
val x = col - 1
|
||||||
val y = row - 1
|
val y = row - 1
|
||||||
@ -118,37 +150,28 @@ object GpuTextBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dst match {
|
dst match {
|
||||||
case dstRam: GpuTextBuffer => src match {
|
case dstScreen: TextBuffer => src match {
|
||||||
case srcRam: GpuTextBuffer => write_vram_to_vram(dstRam, adjustedDstX, adjustedDstY, adjustedWidth, adjustedHeight, srcRam, adjustedSourceX, adjustedSourceY)
|
case srcGpu: GpuTextBuffer => write_vram_to_screen(dstScreen, adjustedDstX, adjustedDstY, adjustedWidth, adjustedHeight, srcGpu, adjustedSourceX, adjustedSourceY)
|
||||||
case srcScreen: traits.TextBufferProxy => write_screen_to_vram(dstRam, adjustedDstX, adjustedDstY, adjustedWidth, adjustedHeight, srcScreen, adjustedSourceX, adjustedSourceY)
|
case _ => throw new UnsupportedOperationException("Source buffer does not support bitblt operations to a screen")
|
||||||
case _ => throw new UnsupportedOperationException("Source buffer does not support bitblt operations")
|
|
||||||
}
|
}
|
||||||
case dstScreen: traits.TextBufferProxy => src match {
|
case dstGpu: GpuTextBuffer => src match {
|
||||||
case srcRam: GpuTextBuffer => write_vram_to_screen(dstScreen, adjustedDstX, adjustedDstY, adjustedWidth, adjustedHeight, srcRam, adjustedSourceX, adjustedSourceY)
|
case srcProxy: TextBufferProxy => write_to_vram(dstGpu, adjustedDstX, adjustedDstY, adjustedWidth, adjustedHeight, srcProxy, adjustedSourceX, adjustedSourceY)
|
||||||
case _: traits.TextBufferProxy => throw new UnsupportedOperationException("Screen to screen bitblt not supported")
|
|
||||||
case _ => throw new UnsupportedOperationException("Source buffer does not support bitblt operations")
|
case _ => throw new UnsupportedOperationException("Source buffer does not support bitblt operations")
|
||||||
}
|
}
|
||||||
case _ => throw new UnsupportedOperationException("Destination buffer does not support bitblt operations")
|
case _ => throw new UnsupportedOperationException("Destination buffer does not support bitblt operations")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def write_vram_to_vram(dstRam: GpuTextBuffer, x: Int, y: Int, w: Int, h: Int, srcRam: GpuTextBuffer, fx: Int, fy: Int): Boolean = {
|
def write_vram_to_screen(dstScreen: TextBuffer, x: Int, y: Int, w: Int, h: Int, srcRam: GpuTextBuffer, fx: Int, fy: Int): Boolean = {
|
||||||
dstRam.data.rawcopy(x + 1, y + 1, w, h, srcRam.data, fx + 1, fx + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
def write_vram_to_screen(dstScreen: traits.TextBufferProxy, x: Int, y: Int, w: Int, h: Int, srcRam: GpuTextBuffer, fx: Int, fy: Int): Boolean = {
|
|
||||||
if (dstScreen.data.rawcopy(x + 1, y + 1, w, h, srcRam.data, fx + 1, fy + 1)) {
|
if (dstScreen.data.rawcopy(x + 1, y + 1, w, h, srcRam.data, fx + 1, fy + 1)) {
|
||||||
// rawcopy returns true only if data was modified
|
// rawcopy returns true only if data was modified
|
||||||
dstScreen.addBuffer(srcRam)
|
dstScreen.addBuffer(srcRam)
|
||||||
dstScreen.onBufferBitBlt(x + 1, y + 1, w, h, srcRam.id, fx + 1, fy + 1)
|
dstScreen.onBufferBitBlt(x + 1, y + 1, w, h, srcRam, fx + 1, fy + 1)
|
||||||
true
|
true
|
||||||
} else false
|
} else false
|
||||||
}
|
}
|
||||||
|
|
||||||
def write_screen_to_vram(dstRam: GpuTextBuffer, x: Int, y: Int, w: Int, h: Int, srcScreen: traits.TextBufferProxy, fx: Int, fy: Int): Boolean = {
|
def write_to_vram(dstRam: GpuTextBuffer, x: Int, y: Int, w: Int, h: Int, src: TextBufferProxy, fx: Int, fy: Int): Boolean = {
|
||||||
val format: PackedColor.ColorFormat = PackedColor.Depth.format(srcScreen.getColorDepth)
|
dstRam.data.rawcopy(x + 1, y + 1, w, h, src.data, fx + 1, fy + 1)
|
||||||
val tempGpu = GpuTextBuffer.wrap(id = -1, new li.cil.oc.util.TextBuffer(w, h, format))
|
|
||||||
tempGpu.data.rawcopy(col = 1, row = 1, w, h, srcScreen.data, fx + 1, fy + 1)
|
|
||||||
write_vram_to_vram(dstRam, x, y, w, h, tempGpu, fx = 0, fy = 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
|||||||
import li.cil.oc.common._
|
import li.cil.oc.common._
|
||||||
import li.cil.oc.common.item.data.NodeData
|
import li.cil.oc.common.item.data.NodeData
|
||||||
import li.cil.oc.common.component.traits.TextBufferProxy
|
import li.cil.oc.common.component.traits.TextBufferProxy
|
||||||
|
import li.cil.oc.common.component.traits.VideoRamRasterizer
|
||||||
import li.cil.oc.server.component.Keyboard
|
import li.cil.oc.server.component.Keyboard
|
||||||
import li.cil.oc.server.{ComponentTracker => ServerComponentTracker}
|
import li.cil.oc.server.{ComponentTracker => ServerComponentTracker}
|
||||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||||
@ -43,7 +44,7 @@ import scala.collection.convert.WrapAsJava._
|
|||||||
import scala.collection.convert.WrapAsScala._
|
import scala.collection.convert.WrapAsScala._
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
|
||||||
class TextBuffer(val host: EnvironmentHost) extends AbstractManagedEnvironment with traits.TextBufferProxy with DeviceInfo {
|
class TextBuffer(val host: EnvironmentHost) extends AbstractManagedEnvironment with traits.TextBufferProxy with VideoRamRasterizer with DeviceInfo {
|
||||||
override val node = api.Network.newNode(this, Visibility.Network).
|
override val node = api.Network.newNode(this, Visibility.Network).
|
||||||
withComponent("screen").
|
withComponent("screen").
|
||||||
withConnector().
|
withConnector().
|
||||||
@ -326,16 +327,16 @@ class TextBuffer(val host: EnvironmentHost) extends AbstractManagedEnvironment w
|
|||||||
proxy.onBufferSet(col, row, s, vertical)
|
proxy.onBufferSet(col, row, s, vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, id: Int, fromCol: Int, fromRow: Int): Unit = {
|
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, id, fromCol, fromRow)
|
proxy.onBufferBitBlt(col, row, w, h, ram, fromCol, fromRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferRamInit(id: Int, ram: TextBufferProxy): Unit = {
|
override def onBufferRamInit(ram: component.GpuTextBuffer): Unit = {
|
||||||
proxy.onBufferRamInit(id, ram)
|
proxy.onBufferRamInit(ram)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferRamDestroy(ids: Array[Int]): Unit = {
|
override def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = {
|
||||||
proxy.onBufferRamDestroy(ids)
|
proxy.onBufferRamDestroy(ram)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def rawSetText(col: Int, row: Int, text: Array[Array[Char]]): Unit = {
|
override def rawSetText(col: Int, row: Int, text: Array[Array[Char]]): Unit = {
|
||||||
@ -568,15 +569,15 @@ object TextBuffer {
|
|||||||
owner.relativeLitArea = -1
|
owner.relativeLitArea = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, id: Int, fromCol: Int, fromRow: Int): Unit = {
|
def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, ram: component.GpuTextBuffer, fromCol: Int, fromRow: Int): Unit = {
|
||||||
owner.relativeLitArea = -1
|
owner.relativeLitArea = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
def onBufferRamInit(id: Int, ram: TextBufferProxy): Unit = {
|
def onBufferRamInit(ram: component.GpuTextBuffer): Unit = {
|
||||||
owner.relativeLitArea = -1
|
owner.relativeLitArea = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
def onBufferRamDestroy(ids: Array[Int]): Unit = {
|
def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = {
|
||||||
owner.relativeLitArea = -1
|
owner.relativeLitArea = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,17 +664,17 @@ object TextBuffer {
|
|||||||
markDirty()
|
markDirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, id: Int, fromCol: Int, fromRow: Int): Unit = {
|
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, id, fromCol, fromRow)
|
super.onBufferBitBlt(col, row, w, h, ram, fromCol, fromRow)
|
||||||
markDirty()
|
markDirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferRamInit(id: Int, buffer: TextBufferProxy): Unit = {
|
override def onBufferRamInit(ram: component.GpuTextBuffer): Unit = {
|
||||||
super.onBufferRamInit(id, buffer)
|
super.onBufferRamInit(ram)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferRamDestroy(ids: Array[Int]): Unit = {
|
override def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = {
|
||||||
super.onBufferRamDestroy(ids)
|
super.onBufferRamDestroy(ram)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def keyDown(character: Char, code: Int, player: EntityPlayer) {
|
override def keyDown(character: Char, code: Int, player: EntityPlayer) {
|
||||||
@ -778,24 +779,24 @@ object TextBuffer {
|
|||||||
owner.synchronized(ServerPacketSender.appendTextBufferSet(owner.pendingCommands, col, row, s, vertical))
|
owner.synchronized(ServerPacketSender.appendTextBufferSet(owner.pendingCommands, col, row, s, vertical))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, id: Int, fromCol: Int, fromRow: Int): Unit = {
|
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, id, fromCol, fromRow)
|
super.onBufferBitBlt(col, row, w, h, ram, fromCol, fromRow)
|
||||||
owner.host.markChanged()
|
owner.host.markChanged()
|
||||||
owner.synchronized(ServerPacketSender.appendTextBufferBitBlt(owner.pendingCommands, col, row, w, h, id, fromCol, fromRow))
|
owner.synchronized(ServerPacketSender.appendTextBufferBitBlt(owner.pendingCommands, col, row, w, h, ram.owner, ram.id, fromCol, fromRow))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferRamInit(id: Int, buffer: TextBufferProxy): Unit = {
|
override def onBufferRamInit(ram: component.GpuTextBuffer): Unit = {
|
||||||
super.onBufferRamInit(id, buffer)
|
super.onBufferRamInit(ram)
|
||||||
owner.host.markChanged()
|
owner.host.markChanged()
|
||||||
val nbt = new NBTTagCompound()
|
val nbt = new NBTTagCompound()
|
||||||
buffer.data.save(nbt)
|
ram.save(nbt)
|
||||||
owner.synchronized(ServerPacketSender.appendTextBufferRamInit(owner.pendingCommands, id, nbt))
|
owner.synchronized(ServerPacketSender.appendTextBufferRamInit(owner.pendingCommands, ram.owner, ram.id, nbt))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferRamDestroy(ids: Array[Int]): Unit = {
|
override def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit = {
|
||||||
super.onBufferRamDestroy(ids)
|
super.onBufferRamDestroy(ram)
|
||||||
owner.host.markChanged()
|
owner.host.markChanged()
|
||||||
owner.synchronized(ServerPacketSender.appendTextBufferRamDestroy(owner.pendingCommands, ids))
|
owner.synchronized(ServerPacketSender.appendTextBufferRamDestroy(owner.pendingCommands, ram.owner, ram.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) {
|
override def onBufferRawSetText(col: Int, row: Int, text: Array[Array[Char]]) {
|
||||||
|
@ -5,7 +5,7 @@ import li.cil.oc.api
|
|||||||
import li.cil.oc.api.internal.TextBuffer
|
import li.cil.oc.api.internal.TextBuffer
|
||||||
import li.cil.oc.util.PackedColor
|
import li.cil.oc.util.PackedColor
|
||||||
|
|
||||||
trait TextBufferProxy extends api.internal.TextBuffer with VideoRamAware {
|
trait TextBufferProxy extends api.internal.TextBuffer {
|
||||||
def data: util.TextBuffer
|
def data: util.TextBuffer
|
||||||
|
|
||||||
override def getWidth: Int = data.width
|
override def getWidth: Int = data.width
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
package li.cil.oc.common.component.traits
|
|
||||||
|
|
||||||
import li.cil.oc.common.component
|
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
|
||||||
|
|
||||||
trait VideoRamAware {
|
|
||||||
private val internalBuffers = new scala.collection.mutable.HashMap[Int, component.GpuTextBuffer]
|
|
||||||
val RESERVED_SCREEN_INDEX: Int = 0
|
|
||||||
|
|
||||||
def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, id: Int, fromCol: Int, fromRow: Int): Unit = {}
|
|
||||||
def onBufferRamInit(id: Int, ram: TextBufferProxy): Unit = {}
|
|
||||||
def onBufferRamDestroy(ids: Array[Int]): Unit = {}
|
|
||||||
|
|
||||||
def bufferIndexes(): Array[Int] = internalBuffers.collect {
|
|
||||||
case (index: Int, _: Any) => index
|
|
||||||
}.toArray
|
|
||||||
|
|
||||||
def addBuffer(buffer: component.GpuTextBuffer): Boolean = {
|
|
||||||
val preexists = internalBuffers.contains(buffer.id)
|
|
||||||
internalBuffers += buffer.id -> buffer
|
|
||||||
if (!preexists || buffer.dirty) {
|
|
||||||
buffer.onBufferRamInit(buffer.id, buffer)
|
|
||||||
onBufferRamInit(buffer.id, buffer)
|
|
||||||
}
|
|
||||||
preexists
|
|
||||||
}
|
|
||||||
|
|
||||||
def removeBuffers(ids: Array[Int]): Boolean = {
|
|
||||||
var allRemoved: Boolean = true
|
|
||||||
if (ids.nonEmpty) {
|
|
||||||
onBufferRamDestroy(ids)
|
|
||||||
for (id <- ids) {
|
|
||||||
if (internalBuffers.remove(id).isEmpty)
|
|
||||||
allRemoved = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allRemoved
|
|
||||||
}
|
|
||||||
|
|
||||||
def removeAllBuffers(): Boolean = removeBuffers(bufferIndexes())
|
|
||||||
|
|
||||||
def loadBuffer(id: Int, nbt: NBTTagCompound): Unit = {
|
|
||||||
val src = new li.cil.oc.util.TextBuffer(width = 1, height = 1, li.cil.oc.util.PackedColor.SingleBitFormat)
|
|
||||||
src.load(nbt)
|
|
||||||
addBuffer(component.GpuTextBuffer.wrap(id, src))
|
|
||||||
}
|
|
||||||
|
|
||||||
def getBuffer(id: Int): Option[component.GpuTextBuffer] = {
|
|
||||||
if (internalBuffers.contains(id))
|
|
||||||
Option(internalBuffers(id))
|
|
||||||
else
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
def nextAvailableBufferIndex: Int = {
|
|
||||||
var index = RESERVED_SCREEN_INDEX + 1
|
|
||||||
while (internalBuffers.contains(index)) {
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
index
|
|
||||||
}
|
|
||||||
|
|
||||||
def calculateUsedMemory(): Int = {
|
|
||||||
var sum: Int = 0
|
|
||||||
for ((_, buffer: component.GpuTextBuffer) <- internalBuffers) {
|
|
||||||
sum += buffer.data.width * buffer.data.height
|
|
||||||
}
|
|
||||||
sum
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,68 @@
|
|||||||
|
package li.cil.oc.common.component.traits
|
||||||
|
|
||||||
|
import li.cil.oc.common.component
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
trait VideoRamDevice {
|
||||||
|
private val internalBuffers = new mutable.HashMap[Int, component.GpuTextBuffer]
|
||||||
|
val RESERVED_SCREEN_INDEX: Int = 0
|
||||||
|
|
||||||
|
def isEmpty: Boolean = internalBuffers.isEmpty
|
||||||
|
|
||||||
|
def onBufferRamDestroy(id: Int): Unit = {}
|
||||||
|
|
||||||
|
def bufferIndexes(): Array[Int] = internalBuffers.collect {
|
||||||
|
case (index: Int, _: Any) => index
|
||||||
|
}.toArray
|
||||||
|
|
||||||
|
def addBuffer(ram: component.GpuTextBuffer): Boolean = {
|
||||||
|
val preexists = internalBuffers.contains(ram.id)
|
||||||
|
internalBuffers += ram.id -> ram
|
||||||
|
preexists
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeBuffers(ids: Array[Int]): Int = {
|
||||||
|
var count = 0
|
||||||
|
if (ids.nonEmpty) {
|
||||||
|
for (id <- ids) {
|
||||||
|
if (internalBuffers.remove(id).nonEmpty) {
|
||||||
|
onBufferRamDestroy(id)
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeAllBuffers(): Int = removeBuffers(bufferIndexes())
|
||||||
|
|
||||||
|
def loadBuffer(address: String, id: Int, nbt: NBTTagCompound): Unit = {
|
||||||
|
val src = new li.cil.oc.util.TextBuffer(width = 1, height = 1, li.cil.oc.util.PackedColor.SingleBitFormat)
|
||||||
|
src.load(nbt)
|
||||||
|
addBuffer(component.GpuTextBuffer.wrap(address, id, src))
|
||||||
|
}
|
||||||
|
|
||||||
|
def getBuffer(id: Int): Option[component.GpuTextBuffer] = {
|
||||||
|
if (internalBuffers.contains(id))
|
||||||
|
Option(internalBuffers(id))
|
||||||
|
else
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
def nextAvailableBufferIndex: Int = {
|
||||||
|
var index = RESERVED_SCREEN_INDEX + 1
|
||||||
|
while (internalBuffers.contains(index)) {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
def calculateUsedMemory(): Int = {
|
||||||
|
var sum: Int = 0
|
||||||
|
for ((_, buffer: component.GpuTextBuffer) <- internalBuffers) {
|
||||||
|
sum += buffer.data.width * buffer.data.height
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package li.cil.oc.common.component.traits
|
||||||
|
|
||||||
|
import li.cil.oc.common.component
|
||||||
|
import li.cil.oc.common.component.GpuTextBuffer
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import net.minecraft.village.VillageDoorInfo
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
trait VideoRamRasterizer {
|
||||||
|
class VirtualRamDevice(val owner: String) extends VideoRamDevice {}
|
||||||
|
private val internalBuffers = new mutable.HashMap[String, VideoRamDevice]
|
||||||
|
|
||||||
|
def onBufferRamInit(ram: component.GpuTextBuffer): Unit
|
||||||
|
def onBufferBitBlt(col: Int, row: Int, w: Int, h: Int, ram: component.GpuTextBuffer, fromCol: Int, fromRow: Int): Unit
|
||||||
|
def onBufferRamDestroy(ram: component.GpuTextBuffer): Unit
|
||||||
|
|
||||||
|
def addBuffer(ram: GpuTextBuffer): Boolean = {
|
||||||
|
var gpu = internalBuffers.get(ram.owner)
|
||||||
|
if (gpu.isEmpty) {
|
||||||
|
gpu = Option(new VirtualRamDevice(ram.owner))
|
||||||
|
internalBuffers += ram.owner -> gpu.get
|
||||||
|
}
|
||||||
|
val preexists: Boolean = gpu.get.addBuffer(ram)
|
||||||
|
if (!preexists || ram.dirty) {
|
||||||
|
onBufferRamInit(ram)
|
||||||
|
}
|
||||||
|
preexists
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeBuffer(owner: String, id: Int): Boolean = {
|
||||||
|
internalBuffers.get(owner) match {
|
||||||
|
case Some(gpu: VideoRamDevice) => {
|
||||||
|
gpu.getBuffer(id) match {
|
||||||
|
case Some(ram: component.GpuTextBuffer) => {
|
||||||
|
onBufferRamDestroy(ram)
|
||||||
|
gpu.removeBuffers(Array(id)) == 1
|
||||||
|
}
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeAllBuffers(owner: String): Int = {
|
||||||
|
var count = 0
|
||||||
|
internalBuffers.get(owner) match {
|
||||||
|
case Some(gpu: VideoRamDevice) => {
|
||||||
|
val ids = gpu.bufferIndexes()
|
||||||
|
for (id <- ids) {
|
||||||
|
if (removeBuffer(owner, id)) {
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ => Unit
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeAllBuffers(): Int = {
|
||||||
|
var count = 0
|
||||||
|
for ((owner: String, _: Any) <- internalBuffers) {
|
||||||
|
count += removeAllBuffers(owner)
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
def loadBuffer(owner: String, id: Int, nbt: NBTTagCompound): Boolean = {
|
||||||
|
val src = new li.cil.oc.util.TextBuffer(width = 1, height = 1, li.cil.oc.util.PackedColor.SingleBitFormat)
|
||||||
|
src.load(nbt)
|
||||||
|
addBuffer(component.GpuTextBuffer.wrap(owner, id, src))
|
||||||
|
}
|
||||||
|
|
||||||
|
def getBuffer(owner: String, id: Int): Option[component.GpuTextBuffer] = {
|
||||||
|
internalBuffers.get(owner) match {
|
||||||
|
case Some(gpu: VideoRamDevice) => gpu.getBuffer(id)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -261,6 +261,8 @@ object Items extends ItemAPI {
|
|||||||
safeGetStack(Constants.ItemName.CraftingUpgrade),
|
safeGetStack(Constants.ItemName.CraftingUpgrade),
|
||||||
safeGetStack(Constants.ItemName.HoverUpgradeTier2),
|
safeGetStack(Constants.ItemName.HoverUpgradeTier2),
|
||||||
safeGetStack(Constants.ItemName.AngelUpgrade),
|
safeGetStack(Constants.ItemName.AngelUpgrade),
|
||||||
|
safeGetStack(Constants.ItemName.TradingUpgrade),
|
||||||
|
safeGetStack(Constants.ItemName.ExperienceUpgrade),
|
||||||
|
|
||||||
safeGetStack(Constants.ItemName.GraphicsCardTier3),
|
safeGetStack(Constants.ItemName.GraphicsCardTier3),
|
||||||
safeGetStack(Constants.ItemName.RedstoneCardTier2),
|
safeGetStack(Constants.ItemName.RedstoneCardTier2),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
package li.cil.oc.common.item
|
package li.cil.oc.common.item
|
||||||
|
|
||||||
class UpgradeTrading(val parent: Delegator) extends traits.Delegate with traits.ItemTier
|
class UpgradeTrading(val parent: Delegator) extends traits.Delegate with traits.ItemTier {
|
||||||
|
override protected def tooltipName: Option[String] = Option(super.unlocalizedName)
|
||||||
|
}
|
||||||
|
@ -32,7 +32,7 @@ import net.minecraftforge.fml.relauncher.Side
|
|||||||
import net.minecraftforge.fml.relauncher.SideOnly
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
|
|
||||||
class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalancer with traits.ComponentInventory with traits.Rotatable with traits.BundledRedstoneAware with Analyzable with internal.Rack with traits.StateAware {
|
class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalancer with traits.ComponentInventory with traits.Rotatable with traits.BundledRedstoneAware with Analyzable with internal.Rack with traits.StateAware {
|
||||||
var isRelayEnabled = true
|
var isRelayEnabled = false
|
||||||
val lastData = new Array[NBTTagCompound](getSizeInventory)
|
val lastData = new Array[NBTTagCompound](getSizeInventory)
|
||||||
val hasChanged: Array[Boolean] = Array.fill(getSizeInventory)(true)
|
val hasChanged: Array[Boolean] = Array.fill(getSizeInventory)(true)
|
||||||
|
|
||||||
|
@ -670,31 +670,31 @@ object PacketSender {
|
|||||||
pb.writeBoolean(vertical)
|
pb.writeBoolean(vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
def appendTextBufferBitBlt(pb: PacketBuilder, col: Int, row: Int, w: Int, h: Int, id: Int, fromCol: Int, fromRow: Int): Unit = {
|
def appendTextBufferBitBlt(pb: PacketBuilder, col: Int, row: Int, w: Int, h: Int, owner: String, id: Int, fromCol: Int, fromRow: Int): Unit = {
|
||||||
pb.writePacketType(PacketType.TextBufferBitBlt)
|
pb.writePacketType(PacketType.TextBufferBitBlt)
|
||||||
|
|
||||||
pb.writeInt(col)
|
pb.writeInt(col)
|
||||||
pb.writeInt(row)
|
pb.writeInt(row)
|
||||||
pb.writeInt(w)
|
pb.writeInt(w)
|
||||||
pb.writeInt(h)
|
pb.writeInt(h)
|
||||||
|
pb.writeUTF(owner)
|
||||||
pb.writeInt(id)
|
pb.writeInt(id)
|
||||||
pb.writeInt(fromCol)
|
pb.writeInt(fromCol)
|
||||||
pb.writeInt(fromRow)
|
pb.writeInt(fromRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
def appendTextBufferRamInit(pb: PacketBuilder, id: Int, nbt: NBTTagCompound): Unit = {
|
def appendTextBufferRamInit(pb: PacketBuilder, address: String, id: Int, nbt: NBTTagCompound): Unit = {
|
||||||
pb.writePacketType(PacketType.TextBufferRamInit)
|
pb.writePacketType(PacketType.TextBufferRamInit)
|
||||||
|
|
||||||
|
pb.writeUTF(address)
|
||||||
pb.writeInt(id)
|
pb.writeInt(id)
|
||||||
pb.writeNBT(nbt)
|
pb.writeNBT(nbt)
|
||||||
}
|
}
|
||||||
|
|
||||||
def appendTextBufferRamDestroy(pb: PacketBuilder, ids: Array[Int]): Unit = {
|
def appendTextBufferRamDestroy(pb: PacketBuilder, owner: String, id: Int): Unit = {
|
||||||
pb.writePacketType(PacketType.TextBufferRamDestroy)
|
pb.writePacketType(PacketType.TextBufferRamDestroy)
|
||||||
pb.writeInt(ids.length)
|
pb.writeUTF(owner)
|
||||||
for (idx <- ids) {
|
pb.writeInt(id)
|
||||||
pb.writeInt(idx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def appendTextBufferRawSetText(pb: PacketBuilder, col: Int, row: Int, text: Array[Array[Char]]) {
|
def appendTextBufferRawSetText(pb: PacketBuilder, col: Int, row: Int, text: Array[Array[Char]]) {
|
||||||
|
@ -211,7 +211,7 @@ class DebugCard(host: EnvironmentHost) extends AbstractManagedEnvironment with D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Callback(doc = """function(x:number, y:number, z:number):boolean -- Connect the debug card to the block at the specified coordinates.""")
|
@Callback(doc = """function(x:number, y:number, z:number):boolean -- Add a component block at the specified coordinates to the computer network.""")
|
||||||
def connectToBlock(context: Context, args: Arguments): Array[AnyRef] = {
|
def connectToBlock(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
checkAccess()
|
checkAccess()
|
||||||
val x = args.checkInteger(0)
|
val x = args.checkInteger(0)
|
||||||
@ -821,7 +821,7 @@ object DebugCard {
|
|||||||
}
|
}
|
||||||
val count = args.checkInteger(1)
|
val count = args.checkInteger(1)
|
||||||
val damage = args.checkInteger(2)
|
val damage = args.checkInteger(2)
|
||||||
val tagJson = args.checkString(3)
|
val tagJson = args.optString(3, "")
|
||||||
val tag = if (Strings.isNullOrEmpty(tagJson)) null else JsonToNBT.getTagFromJson(tagJson)
|
val tag = if (Strings.isNullOrEmpty(tagJson)) null else JsonToNBT.getTagFromJson(tagJson)
|
||||||
val position = BlockPosition(args.checkDouble(4), args.checkDouble(5), args.checkDouble(6), world)
|
val position = BlockPosition(args.checkDouble(4), args.checkDouble(5), args.checkDouble(6), world)
|
||||||
val side = args.checkSideAny(7)
|
val side = args.checkSideAny(7)
|
||||||
|
@ -7,9 +7,7 @@ import li.cil.oc.api.Network
|
|||||||
import li.cil.oc.api.driver.DeviceInfo
|
import li.cil.oc.api.driver.DeviceInfo
|
||||||
import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute
|
import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute
|
||||||
import li.cil.oc.api.driver.DeviceInfo.DeviceClass
|
import li.cil.oc.api.driver.DeviceInfo.DeviceClass
|
||||||
import li.cil.oc.api.machine.Arguments
|
import li.cil.oc.api.machine.{Arguments, Callback, Context, LimitReachedException}
|
||||||
import li.cil.oc.api.machine.Callback
|
|
||||||
import li.cil.oc.api.machine.Context
|
|
||||||
import li.cil.oc.api.network._
|
import li.cil.oc.api.network._
|
||||||
import li.cil.oc.api.prefab
|
import li.cil.oc.api.prefab
|
||||||
import li.cil.oc.api.prefab.AbstractManagedEnvironment
|
import li.cil.oc.api.prefab.AbstractManagedEnvironment
|
||||||
@ -33,7 +31,7 @@ import scala.util.matching.Regex
|
|||||||
// saved, but before the computer was saved, leading to mismatching states in
|
// saved, but before the computer was saved, leading to mismatching states in
|
||||||
// the save file - a Bad Thing (TM).
|
// the save file - a Bad Thing (TM).
|
||||||
|
|
||||||
class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with DeviceInfo with component.traits.VideoRamAware {
|
class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with DeviceInfo with component.traits.VideoRamDevice {
|
||||||
override val node = Network.newNode(this, Visibility.Neighbors).
|
override val node = Network.newNode(this, Visibility.Neighbors).
|
||||||
withComponent("gpu").
|
withComponent("gpu").
|
||||||
withConnector().
|
withConnector().
|
||||||
@ -71,8 +69,13 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
final val setCosts = Array(1.0 / 64, 1.0 / 128, 1.0 / 256)
|
final val setCosts = Array(1.0 / 64, 1.0 / 128, 1.0 / 256)
|
||||||
final val copyCosts = Array(1.0 / 16, 1.0 / 32, 1.0 / 64)
|
final val copyCosts = Array(1.0 / 16, 1.0 / 32, 1.0 / 64)
|
||||||
final val fillCosts = Array(1.0 / 32, 1.0 / 64, 1.0 / 128)
|
final val fillCosts = Array(1.0 / 32, 1.0 / 64, 1.0 / 128)
|
||||||
final val bitbltCosts = Array(32, 16, 8)
|
// These are dirty page bitblt budget costs
|
||||||
final val totalVRAM: Int = (maxResolution._1 * maxResolution._2) * Settings.get.vramSizes(0 max tier min Settings.get.vramSizes.length)
|
// a single bitblt can send a screen of data, which is n*set calls where set is writing an entire line
|
||||||
|
// So for each tier, we multiple the set cost with the number of lines the screen may have
|
||||||
|
final val bitbltCost: Double = Settings.get.bitbltCost * scala.math.pow(2, tier)
|
||||||
|
final val totalVRAM: Double = (maxResolution._1 * maxResolution._2) * Settings.get.vramSizes(0 max tier min 2)
|
||||||
|
|
||||||
|
var budgetExhausted: Boolean = false // for especially expensive calls, bitblt
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
@ -96,12 +99,12 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
private def consumeViewportPower(buffer: api.internal.TextBuffer, context: Context, budgetCost: Double, units: Int, factor: Double): Boolean = {
|
private def resolveInvokeCosts(idx: Int, context: Context, budgetCost: Double, units: Int, factor: Double): Boolean = {
|
||||||
buffer match {
|
idx match {
|
||||||
case _: component.GpuTextBuffer => true
|
case RESERVED_SCREEN_INDEX =>
|
||||||
case _ =>
|
|
||||||
context.consumeCallBudget(budgetCost)
|
context.consumeCallBudget(budgetCost)
|
||||||
consumePower(units, factor)
|
consumePower(units, factor)
|
||||||
|
case _ => true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,38 +143,40 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
}
|
}
|
||||||
else if (size > (totalVRAM - calculateUsedMemory)) {
|
else if (size > (totalVRAM - calculateUsedMemory)) {
|
||||||
result(Unit, "not enough video memory")
|
result(Unit, "not enough video memory")
|
||||||
|
} else if (node == null) {
|
||||||
|
result(Unit, "graphics card appears disconnected")
|
||||||
} else {
|
} else {
|
||||||
val format: PackedColor.ColorFormat = PackedColor.Depth.format(Settings.screenDepthsByTier(tier))
|
val format: PackedColor.ColorFormat = PackedColor.Depth.format(Settings.screenDepthsByTier(tier))
|
||||||
val buffer = new li.cil.oc.util.TextBuffer(width, height, format)
|
val buffer = new li.cil.oc.util.TextBuffer(width, height, format)
|
||||||
val page = component.GpuTextBuffer.wrap(nextAvailableBufferIndex, buffer)
|
val page = component.GpuTextBuffer.wrap(node.address, nextAvailableBufferIndex, buffer)
|
||||||
addBuffer(page)
|
addBuffer(page)
|
||||||
result(page.id)
|
result(page.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this event occurs when the gpu is told a page was removed - we need to notify the screen of this
|
// this event occurs when the gpu is told a page was removed - we need to notify the screen of this
|
||||||
// we do this because the VideoRamAware trait only notifies itself, it doesn't assume there is a screen
|
// we do this because the VideoRamDevice trait only notifies itself, it doesn't assume there is a screen
|
||||||
override def onBufferRamDestroy(ids: Array[Int]): Unit = {
|
override def onBufferRamDestroy(id: Int): Unit = {
|
||||||
// first protect our buffer index - it needs to fall back to the screen if its buffer was removed
|
// first protect our buffer index - it needs to fall back to the screen if its buffer was removed
|
||||||
if (ids.contains(bufferIndex)) {
|
if (id != RESERVED_SCREEN_INDEX) {
|
||||||
bufferIndex = RESERVED_SCREEN_INDEX
|
|
||||||
}
|
|
||||||
if (ids.nonEmpty) {
|
|
||||||
screen(RESERVED_SCREEN_INDEX, s => s match {
|
screen(RESERVED_SCREEN_INDEX, s => s match {
|
||||||
case oc: component.traits.VideoRamAware => result(oc.removeBuffers(ids))
|
case oc: component.traits.VideoRamRasterizer => result(oc.removeBuffer(node.address, id))
|
||||||
case _ => result(true)// addon mod screen type that is not video ram aware
|
case _ => result(true)// addon mod screen type that is not video ram aware
|
||||||
})
|
})
|
||||||
} else result(true)
|
}
|
||||||
|
if (id == bufferIndex) {
|
||||||
|
bufferIndex = RESERVED_SCREEN_INDEX
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Callback(direct = true, doc = """function(index: number): boolean -- Closes buffer at `index`. Returns true if a buffer closed. If the current buffer is closed, index moves to 0""")
|
@Callback(direct = true, doc = """function(index: number): boolean -- Closes buffer at `index`. Returns true if a buffer closed. If the current buffer is closed, index moves to 0""")
|
||||||
def freeBuffer(context: Context, args: Arguments): Array[AnyRef] = {
|
def freeBuffer(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val index: Int = args.optInteger(0, bufferIndex)
|
val index: Int = args.optInteger(0, bufferIndex)
|
||||||
if (removeBuffers(Array(index))) result(true)
|
if (removeBuffers(Array(index)) == 1) result(true)
|
||||||
else result(Unit, "no buffer at index")
|
else result(Unit, "no buffer at index")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Callback(direct = true, doc = """function(): number -- Closes all buffers and returns true on success. If the active buffer is closed, index moves to 0""")
|
@Callback(direct = true, doc = """function(): number -- Closes all buffers and returns the count. If the active buffer is closed, index moves to 0""")
|
||||||
def freeAllBuffers(context: Context, args: Arguments): Array[AnyRef] = result(removeAllBuffers())
|
def freeAllBuffers(context: Context, args: Arguments): Array[AnyRef] = result(removeAllBuffers())
|
||||||
|
|
||||||
@Callback(direct = true, doc = """function(): number -- returns the total memory size of the gpu vram. This does not include the screen.""")
|
@Callback(direct = true, doc = """function(): number -- returns the total memory size of the gpu vram. This does not include the screen.""")
|
||||||
@ -194,13 +199,14 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
// large dirty buffers need throttling so their budget cost is more
|
// large dirty buffers need throttling so their budget cost is more
|
||||||
// clean buffers have no budget cost.
|
// clean buffers have no budget cost.
|
||||||
src match {
|
src match {
|
||||||
case page: GpuTextBuffer if page.dirty => dst match {
|
case page: GpuTextBuffer => dst match {
|
||||||
case _: GpuTextBuffer => 0.0 // no cost to write to ram
|
case _: GpuTextBuffer => 0.0 // no cost to write to ram
|
||||||
case _ => // screen target will need the new buffer
|
case _ if page.dirty => // screen target will need the new buffer
|
||||||
// small buffers are cheap, so increase with size of buffer source
|
// small buffers are cheap, so increase with size of buffer source
|
||||||
bitbltCosts(tier) * (src.getWidth * src.getHeight) / (maxResolution._1 * maxResolution._2)
|
bitbltCost * (src.getWidth * src.getHeight) / (maxResolution._1 * maxResolution._2)
|
||||||
|
case _ => .001 // bitblt a clean page to screen has a minimal cost
|
||||||
}
|
}
|
||||||
case _ => 0.0 // from screen or from clean buffer is free
|
case _ => 0.0 // from screen is free
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +215,7 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
// rasterizing to the screen has the same cost as copy (in fact, screen-to-screen blt _is_ a copy
|
// rasterizing to the screen has the same cost as copy (in fact, screen-to-screen blt _is_ a copy
|
||||||
dst match {
|
dst match {
|
||||||
case _: GpuTextBuffer => 0
|
case _: GpuTextBuffer => 0
|
||||||
case _ => Settings.get.gpuCopyCost / (maxResolution._1 * maxResolution._2)
|
case _ => Settings.get.gpuCopyCost / 15
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,10 +232,27 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
val fromCol = args.optInteger(6, 1)
|
val fromCol = args.optInteger(6, 1)
|
||||||
val fromRow = args.optInteger(7, 1)
|
val fromRow = args.optInteger(7, 1)
|
||||||
|
|
||||||
val budgetCost: Double = determineBitbltBudgetCost(dst, src)
|
var budgetCost: Double = determineBitbltBudgetCost(dst, src)
|
||||||
val energyCost: Double = determineBitbltEnergyCost(dst)
|
val energyCost: Double = determineBitbltEnergyCost(dst)
|
||||||
|
val tierCredit: Double = ((tier + 1) * .5)
|
||||||
|
val overBudget: Double = budgetCost - tierCredit
|
||||||
|
|
||||||
if (consumeViewportPower(dst, context, budgetCost, w * h, energyCost)) {
|
if (overBudget > 0) {
|
||||||
|
if (budgetExhausted) { // we've thrown once before
|
||||||
|
if (overBudget > tierCredit) { // we need even more pause than just a single tierCredit
|
||||||
|
val pauseNeeded = overBudget - tierCredit
|
||||||
|
val seconds: Double = (pauseNeeded / tierCredit) / 20
|
||||||
|
context.pause(seconds)
|
||||||
|
}
|
||||||
|
budgetCost = 0 // remove the rest of the budget cost at this point
|
||||||
|
} else {
|
||||||
|
budgetExhausted = true
|
||||||
|
throw new LimitReachedException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
budgetExhausted = false
|
||||||
|
|
||||||
|
if (resolveInvokeCosts(dstIdx, context, budgetCost, w * h, energyCost)) {
|
||||||
if (dstIdx == srcIdx) {
|
if (dstIdx == srcIdx) {
|
||||||
val tx = col - fromCol
|
val tx = col - fromCol
|
||||||
val ty = row - fromRow
|
val ty = row - fromRow
|
||||||
@ -264,7 +287,7 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
s.setForegroundColor(0xFFFFFF)
|
s.setForegroundColor(0xFFFFFF)
|
||||||
s.setBackgroundColor(0x000000)
|
s.setBackgroundColor(0x000000)
|
||||||
s match {
|
s match {
|
||||||
case oc: component.traits.VideoRamAware => oc.removeAllBuffers()
|
case oc: component.traits.VideoRamRasterizer => oc.removeAllBuffers()
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,13 +299,7 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Callback(direct = true, doc = """function():string -- Get the address of the screen the GPU is currently bound to.""")
|
@Callback(direct = true, doc = """function():string -- Get the address of the screen the GPU is currently bound to.""")
|
||||||
def getScreen(context: Context, args: Arguments): Array[AnyRef] = {
|
def getScreen(context: Context, args: Arguments): Array[AnyRef] = screen(RESERVED_SCREEN_INDEX, s => result(s.node.address))
|
||||||
if (bufferIndex == RESERVED_SCREEN_INDEX) {
|
|
||||||
screen(s => result(s.node.address))
|
|
||||||
} else {
|
|
||||||
result(Unit, "the current text buffer is video ram")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Callback(direct = true, doc = """function():number, boolean -- Get the current background color and whether it's from the palette or not.""")
|
@Callback(direct = true, doc = """function():number, boolean -- Get the current background color and whether it's from the palette or not.""")
|
||||||
def getBackground(context: Context, args: Arguments): Array[AnyRef] =
|
def getBackground(context: Context, args: Arguments): Array[AnyRef] =
|
||||||
@ -290,8 +307,10 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
|
|
||||||
@Callback(direct = true, doc = """function(value:number[, palette:boolean]):number, number or nil -- Sets the background color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.""")
|
@Callback(direct = true, doc = """function(value:number[, palette:boolean]):number, number or nil -- Sets the background color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.""")
|
||||||
def setBackground(context: Context, args: Arguments): Array[AnyRef] = {
|
def setBackground(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
context.consumeCallBudget(setBackgroundCosts(tier))
|
|
||||||
val color = args.checkInteger(0)
|
val color = args.checkInteger(0)
|
||||||
|
if (bufferIndex == RESERVED_SCREEN_INDEX) {
|
||||||
|
context.consumeCallBudget(setBackgroundCosts(tier))
|
||||||
|
}
|
||||||
screen(s => {
|
screen(s => {
|
||||||
val oldValue = s.getBackgroundColor
|
val oldValue = s.getBackgroundColor
|
||||||
val (oldColor, oldIndex) =
|
val (oldColor, oldIndex) =
|
||||||
@ -312,8 +331,10 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
|
|
||||||
@Callback(direct = true, doc = """function(value:number[, palette:boolean]):number, number or nil -- Sets the foreground color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.""")
|
@Callback(direct = true, doc = """function(value:number[, palette:boolean]):number, number or nil -- Sets the foreground color to the specified value. Optionally takes an explicit palette index. Returns the old value and if it was from the palette its palette index.""")
|
||||||
def setForeground(context: Context, args: Arguments): Array[AnyRef] = {
|
def setForeground(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
context.consumeCallBudget(setForegroundCosts(tier))
|
|
||||||
val color = args.checkInteger(0)
|
val color = args.checkInteger(0)
|
||||||
|
if (bufferIndex == RESERVED_SCREEN_INDEX) {
|
||||||
|
context.consumeCallBudget(setForegroundCosts(tier))
|
||||||
|
}
|
||||||
screen(s => {
|
screen(s => {
|
||||||
val oldValue = s.getForegroundColor
|
val oldValue = s.getForegroundColor
|
||||||
val (oldColor, oldIndex) =
|
val (oldColor, oldIndex) =
|
||||||
@ -338,10 +359,12 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
|
|
||||||
@Callback(direct = true, doc = """function(index:number, color:number):number -- Set the palette color at the specified palette index. Returns the previous value.""")
|
@Callback(direct = true, doc = """function(index:number, color:number):number -- Set the palette color at the specified palette index. Returns the previous value.""")
|
||||||
def setPaletteColor(context: Context, args: Arguments): Array[AnyRef] = {
|
def setPaletteColor(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
context.consumeCallBudget(setPaletteColorCosts(tier))
|
|
||||||
val index = args.checkInteger(0)
|
val index = args.checkInteger(0)
|
||||||
val color = args.checkInteger(1)
|
val color = args.checkInteger(1)
|
||||||
context.pause(0.1)
|
if (bufferIndex == RESERVED_SCREEN_INDEX) {
|
||||||
|
context.consumeCallBudget(setPaletteColorCosts(tier))
|
||||||
|
context.pause(0.1)
|
||||||
|
}
|
||||||
screen(s => try {
|
screen(s => try {
|
||||||
val oldColor = s.getPaletteColor(index)
|
val oldColor = s.getPaletteColor(index)
|
||||||
s.setPaletteColor(index, color)
|
s.setPaletteColor(index, color)
|
||||||
@ -422,6 +445,16 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
|
|
||||||
@Callback(direct = true, doc = """function(x:number, y:number):string, number, number, number or nil, number or nil -- Get the value displayed on the screen at the specified index, as well as the foreground and background color. If the foreground or background is from the palette, returns the palette indices as fourth and fifth results, else nil, respectively.""")
|
@Callback(direct = true, doc = """function(x:number, y:number):string, number, number, number or nil, number or nil -- Get the value displayed on the screen at the specified index, as well as the foreground and background color. If the foreground or background is from the palette, returns the palette indices as fourth and fifth results, else nil, respectively.""")
|
||||||
def get(context: Context, args: Arguments): Array[AnyRef] = {
|
def get(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
|
// maybe one day:
|
||||||
|
// if (bufferIndex != RESERVED_SCREEN_INDEX && args.count() == 0) {
|
||||||
|
// return screen {
|
||||||
|
// case ram: GpuTextBuffer => {
|
||||||
|
// val nbt = new NBTTagCompound
|
||||||
|
// ram.data.save(nbt)
|
||||||
|
// result(nbt)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
val x = args.checkInteger(0) - 1
|
val x = args.checkInteger(0) - 1
|
||||||
val y = args.checkInteger(1) - 1
|
val y = args.checkInteger(1) - 1
|
||||||
screen(s => {
|
screen(s => {
|
||||||
@ -455,11 +488,10 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
val vertical = args.optBoolean(3, false)
|
val vertical = args.optBoolean(3, false)
|
||||||
|
|
||||||
screen(s => {
|
screen(s => {
|
||||||
if (consumeViewportPower(s, context, setCosts(tier), value.length, Settings.get.gpuSetCost)) {
|
if (resolveInvokeCosts(bufferIndex, context, setCosts(tier), value.length, Settings.get.gpuSetCost)) {
|
||||||
s.set(x, y, value, vertical)
|
s.set(x, y, value, vertical)
|
||||||
result(true)
|
result(true)
|
||||||
}
|
} else result(Unit, "not enough energy")
|
||||||
else result(Unit, "not enough energy")
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,7 +504,7 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
val tx = args.checkInteger(4)
|
val tx = args.checkInteger(4)
|
||||||
val ty = args.checkInteger(5)
|
val ty = args.checkInteger(5)
|
||||||
screen(s => {
|
screen(s => {
|
||||||
if (consumeViewportPower(s, context, copyCosts(tier), w * h, Settings.get.gpuCopyCost)) {
|
if (resolveInvokeCosts(bufferIndex, context, copyCosts(tier), w * h, Settings.get.gpuCopyCost)) {
|
||||||
s.copy(x, y, w, h, tx, ty)
|
s.copy(x, y, w, h, tx, ty)
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
@ -490,7 +522,7 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
if (value.length == 1) screen(s => {
|
if (value.length == 1) screen(s => {
|
||||||
val c = value.charAt(0)
|
val c = value.charAt(0)
|
||||||
val cost = if (c == ' ') Settings.get.gpuClearCost else Settings.get.gpuFillCost
|
val cost = if (c == ' ') Settings.get.gpuClearCost else Settings.get.gpuFillCost
|
||||||
if (consumeViewportPower(s, context, fillCosts(tier), w * h, cost)) {
|
if (resolveInvokeCosts(bufferIndex, context, fillCosts(tier), w * h, cost)) {
|
||||||
s.fill(x, y, w, h, value.charAt(0))
|
s.fill(x, y, w, h, value.charAt(0))
|
||||||
result(true)
|
result(true)
|
||||||
}
|
}
|
||||||
@ -608,7 +640,7 @@ class GraphicsCard(val tier: Int) extends AbstractManagedEnvironment with Device
|
|||||||
val nbtPage = nbtPages.getCompoundTagAt(i)
|
val nbtPage = nbtPages.getCompoundTagAt(i)
|
||||||
val idx: Int = nbtPage.getInteger(NBT_PAGE_IDX)
|
val idx: Int = nbtPage.getInteger(NBT_PAGE_IDX)
|
||||||
val data = nbtPage.getCompoundTag(NBT_PAGE_DATA)
|
val data = nbtPage.getCompoundTag(NBT_PAGE_DATA)
|
||||||
loadBuffer(idx, data)
|
loadBuffer(node.address, idx, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,27 +102,32 @@ class Trade(val info: TradeInfo) extends AbstractValue {
|
|||||||
|
|
||||||
def completeTrade(inventory: IInventory, recipe: MerchantRecipe, exact: Boolean) : Boolean = {
|
def completeTrade(inventory: IInventory, recipe: MerchantRecipe, exact: Boolean) : Boolean = {
|
||||||
// Now we'll check if we have enough items to perform the trade, caching first
|
// Now we'll check if we have enough items to perform the trade, caching first
|
||||||
val firstInputStack = recipe.getItemToBuy
|
info.merchant.get match {
|
||||||
val secondInputStack = if (recipe.hasSecondItemToBuy) Option(recipe.getSecondItemToBuy) else None
|
case Some(merchant) => {
|
||||||
|
val firstInputStack = recipe.getItemToBuy
|
||||||
|
val secondInputStack = if (recipe.hasSecondItemToBuy) Option(recipe.getSecondItemToBuy) else None
|
||||||
|
|
||||||
def containsAccumulativeItemStack(stack: ItemStack) =
|
def containsAccumulativeItemStack(stack: ItemStack) =
|
||||||
InventoryUtils.extractFromInventory(stack, inventory, null, simulate = true, exact = exact).getCount == 0
|
InventoryUtils.extractFromInventory(stack, inventory, null, simulate = true, exact = exact).getCount == 0
|
||||||
|
|
||||||
// Check if we have enough to perform the trade.
|
// Check if we have enough to perform the trade.
|
||||||
if (!containsAccumulativeItemStack(firstInputStack) || !secondInputStack.forall(containsAccumulativeItemStack))
|
if (!containsAccumulativeItemStack(firstInputStack) || !secondInputStack.forall(containsAccumulativeItemStack))
|
||||||
return false
|
return false
|
||||||
|
|
||||||
// Now we need to check if we have enough inventory space to accept the item we get for the trade.
|
// Now we need to check if we have enough inventory space to accept the item we get for the trade.
|
||||||
val outputStack = recipe.getItemToSell.copy()
|
val outputStack = recipe.getItemToSell.copy()
|
||||||
|
|
||||||
// We established that out inventory allows to perform the trade, now actually do the trade.
|
// We established that out inventory allows to perform the trade, now actually do the trade.
|
||||||
InventoryUtils.extractFromInventory(firstInputStack, InventoryUtils.asItemHandler(inventory), exact = exact)
|
InventoryUtils.extractFromInventory(firstInputStack, InventoryUtils.asItemHandler(inventory), exact = exact)
|
||||||
secondInputStack.map(InventoryUtils.extractFromInventory(_, InventoryUtils.asItemHandler(inventory), exact = exact))
|
secondInputStack.map(InventoryUtils.extractFromInventory(_, InventoryUtils.asItemHandler(inventory), exact = exact))
|
||||||
InventoryUtils.insertIntoInventory(outputStack, InventoryUtils.asItemHandler(inventory), outputStack.getCount)
|
InventoryUtils.insertIntoInventory(outputStack, InventoryUtils.asItemHandler(inventory), outputStack.getCount)
|
||||||
|
|
||||||
// Tell the merchant we used the recipe, so MC can disable it and/or enable more recipes.
|
// Tell the merchant we used the recipe, so MC can disable it and/or enable more recipes.
|
||||||
info.merchant.get.orNull.useRecipe(recipe)
|
merchant.useRecipe(recipe)
|
||||||
true
|
true
|
||||||
|
}
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ class Machine(val host: MachineHost) extends AbstractManagedEnvironment with mac
|
|||||||
|
|
||||||
override def consumeCallBudget(callCost: Double): Unit = {
|
override def consumeCallBudget(callCost: Double): Unit = {
|
||||||
if (architecture.isInitialized && !inSynchronizedCall) {
|
if (architecture.isInitialized && !inSynchronizedCall) {
|
||||||
val clampedCost = math.max(0.001, callCost)
|
val clampedCost = math.max(0.0, callCost)
|
||||||
if (clampedCost > callBudget) {
|
if (clampedCost > callBudget) {
|
||||||
throw new LimitReachedException()
|
throw new LimitReachedException()
|
||||||
}
|
}
|
||||||
|
49
src/main/scala/li/cil/oc/util/NbtDataStream.scala
Normal file
49
src/main/scala/li/cil/oc/util/NbtDataStream.scala
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package li.cil.oc.util
|
||||||
|
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
|
||||||
|
object NbtDataStream {
|
||||||
|
def getShortArray(nbt: NBTTagCompound, key: String, array2d: Array[Array[Short]], w: Int, h: Int) : Boolean = {
|
||||||
|
if (!nbt.hasKey(key)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val rawByteReader = new java.io.ByteArrayInputStream(nbt.getByteArray(key))
|
||||||
|
val memReader = new java.io.DataInputStream(rawByteReader)
|
||||||
|
for (y <- 0 until h) {
|
||||||
|
for (x <- 0 until w) {
|
||||||
|
if (2 > memReader.available()) {
|
||||||
|
return true // not great, but get out now
|
||||||
|
}
|
||||||
|
array2d(y)(x) = memReader.readShort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
def getIntArrayLegacy(nbt: NBTTagCompound, key: String, array2d: Array[Array[Short]], w: Int, h: Int) : Boolean = {
|
||||||
|
if (!nbt.hasKey(key)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// legacy format
|
||||||
|
val c = nbt.getIntArray(key)
|
||||||
|
for (y <- 0 until h) {
|
||||||
|
val rowColor = array2d(y)
|
||||||
|
for (x <- 0 until w) {
|
||||||
|
val index = x + y * w
|
||||||
|
if (index >= c.length) {
|
||||||
|
return true // not great, but, the read at least started
|
||||||
|
}
|
||||||
|
rowColor(x) = c(index).toShort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
def setShortArray(nbt: NBTTagCompound, key: String, array: Array[Short]): Unit = {
|
||||||
|
val rawByteWriter = new java.io.ByteArrayOutputStream()
|
||||||
|
val memWriter = new java.io.DataOutputStream(rawByteWriter)
|
||||||
|
array.foreach(memWriter.writeShort(_))
|
||||||
|
nbt.setByteArray(key, rawByteWriter.toByteArray)
|
||||||
|
}
|
||||||
|
}
|
@ -215,7 +215,14 @@ class TextBuffer(var width: Int, var height: Int, initialFormat: PackedColor.Col
|
|||||||
val dstColorLine = color(row_index + yOffset)
|
val dstColorLine = color(row_index + yOffset)
|
||||||
for (xOffset <- 0 until w) {
|
for (xOffset <- 0 until w) {
|
||||||
val srcChar = src.buffer(fromRow + yOffset - 1)(fromCol + xOffset - 1)
|
val srcChar = src.buffer(fromRow + yOffset - 1)(fromCol + xOffset - 1)
|
||||||
val srcColor = src.color(fromRow + yOffset - 1)(fromCol + xOffset - 1)
|
var srcColor = src.color(fromRow + yOffset - 1)(fromCol + xOffset - 1)
|
||||||
|
|
||||||
|
if (this.format.depth != src.format.depth) {
|
||||||
|
val fg = PackedColor.Color(PackedColor.unpackForeground(srcColor, src.format))
|
||||||
|
val bg = PackedColor.Color(PackedColor.unpackBackground(srcColor, src.format))
|
||||||
|
srcColor = PackedColor.pack(fg, bg, format)
|
||||||
|
}
|
||||||
|
|
||||||
if (srcChar != dstCharLine(col_index + xOffset) || srcColor != dstColorLine(col_index + xOffset)) {
|
if (srcChar != dstCharLine(col_index + xOffset) || srcColor != dstColorLine(col_index + xOffset)) {
|
||||||
changed = true
|
changed = true
|
||||||
dstCharLine(col_index + xOffset) = srcChar
|
dstCharLine(col_index + xOffset) = srcChar
|
||||||
@ -262,15 +269,8 @@ class TextBuffer(var width: Int, var height: Int, initialFormat: PackedColor.Col
|
|||||||
foreground = PackedColor.Color(nbt.getInteger("foreground"), nbt.getBoolean("foregroundIsPalette"))
|
foreground = PackedColor.Color(nbt.getInteger("foreground"), nbt.getBoolean("foregroundIsPalette"))
|
||||||
background = PackedColor.Color(nbt.getInteger("background"), nbt.getBoolean("backgroundIsPalette"))
|
background = PackedColor.Color(nbt.getInteger("background"), nbt.getBoolean("backgroundIsPalette"))
|
||||||
|
|
||||||
val c = nbt.getIntArray("color")
|
if (!NbtDataStream.getShortArray(nbt, "colors", color, w, h)) {
|
||||||
for (i <- 0 until h) {
|
NbtDataStream.getIntArrayLegacy(nbt, "color", color, w, h)
|
||||||
val rowColor = color(i)
|
|
||||||
for (j <- 0 until w) {
|
|
||||||
val index = j + i * w
|
|
||||||
if (index < c.length) {
|
|
||||||
rowColor(j) = c(index).toShort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,10 +291,10 @@ class TextBuffer(var width: Int, var height: Int, initialFormat: PackedColor.Col
|
|||||||
nbt.setInteger("background", _background.value)
|
nbt.setInteger("background", _background.value)
|
||||||
nbt.setBoolean("backgroundIsPalette", _background.isPalette)
|
nbt.setBoolean("backgroundIsPalette", _background.isPalette)
|
||||||
|
|
||||||
nbt.setTag("color", new NBTTagIntArray(color.flatten.map(_.toInt)))
|
NbtDataStream.setShortArray(nbt, "colors", color.flatten.map(_.toShort))
|
||||||
}
|
}
|
||||||
|
|
||||||
override def toString = {
|
override def toString: String = {
|
||||||
val b = StringBuilder.newBuilder
|
val b = StringBuilder.newBuilder
|
||||||
if (buffer.length > 0) {
|
if (buffer.length > 0) {
|
||||||
b.appendAll(buffer(0))
|
b.appendAll(buffer(0))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user