diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/java/li/cil/oc/api/prefab/ItemStackArrayValue.java b/src/main/java/li/cil/oc/api/prefab/ItemStackArrayValue.java new file mode 100644 index 000000000..e8ac07d70 --- /dev/null +++ b/src/main/java/li/cil/oc/api/prefab/ItemStackArrayValue.java @@ -0,0 +1,136 @@ +package li.cil.oc.api.prefab; + +import li.cil.oc.api.machine.Arguments; +import li.cil.oc.api.machine.Callback; +import li.cil.oc.api.machine.Context; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; + +import java.util.HashMap; +import java.util.TreeMap; + +public class ItemStackArrayValue extends AbstractValue { + + private ItemStack[] array = null; + private int iteratorIndex; + + private static final byte TAGLIST_ID = (new NBTTagList()).getId(); + private static final byte COMPOUND_ID = (new NBTTagCompound()).getId(); + private static final String ARRAY_KEY = "Array"; + private static final String INDEX_KEY = "Index"; + + private static final HashMap emptyMap = new HashMap(); + + public ItemStackArrayValue(ItemStack[] arr){ + if (arr != null){ + this.array = new ItemStack[arr.length]; + for (int i=0; i< arr.length; i++){ + this.array[i] = arr[i] != null ? arr[i].copy() : null; + } + } + this.iteratorIndex = 0; + } + + public ItemStackArrayValue(){ + this(null); + } + + @Override + public Object[] call(Context context, Arguments arguments) { + if (this.array == null) + return null; + if (this.iteratorIndex >= this.array.length) + return null; + int index = this.iteratorIndex++; + if (this.array[index] == null || this.array[index].isEmpty()) + return new Object[]{ emptyMap }; + return new Object[]{ this.array[index] != null ? this.array[index] : emptyMap }; + } + + @Override + public Object apply(Context context, Arguments arguments) { + if (arguments.count() == 0 || this.array == null) + return null; + if (arguments.isInteger(0)){//index access + int luaIndex = arguments.checkInteger(0); + if (luaIndex > this.array.length || luaIndex < 1){ + return null; + } + return this.array[luaIndex-1]; + } + if (arguments.isString(0)){ + String arg = arguments.checkString(0); + if (arg.equals("n")){ + return this.array.length; + } + } + return null; + } + + @Override + public void load(NBTTagCompound nbt) { + if (nbt.hasKey(ARRAY_KEY, TAGLIST_ID)){ + NBTTagList tagList = nbt.getTagList(ARRAY_KEY,COMPOUND_ID); + this.array = new ItemStack[tagList.tagCount()]; + for (int i = 0; i < tagList.tagCount(); ++i){ + NBTTagCompound el = tagList.getCompoundTagAt(i); + if (el.hasNoTags()) + this.array[i] = ItemStack.EMPTY; + else + this.array[i] = new ItemStack(el); + } + } else { + this.array = null; + } + this.iteratorIndex = nbt.getInteger(INDEX_KEY); + } + + @Override + public void save(NBTTagCompound nbt) { + + NBTTagCompound nullnbt = new NBTTagCompound(); + + if (this.array != null) { + NBTTagList nbttaglist = new NBTTagList(); + for (ItemStack stack : this.array) { + if (stack != null) { + NBTBase nbttagcompound = stack.serializeNBT(); + nbttaglist.appendTag(nbttagcompound); + } else { + nbttaglist.appendTag(nullnbt); + } + } + + nbt.setTag(ARRAY_KEY, nbttaglist); + } + + nbt.setInteger(INDEX_KEY, iteratorIndex); + } + + @Callback(doc="function():nil -- Reset the iterator index so that the next call will return the first element.") + public Object[] reset(Context context, Arguments arguments) throws Exception { + this.iteratorIndex = 0; + return null; + } + + @Callback(doc="function():number -- Returns the number of elements in the this.array.") + public Object[] count(Context context, Arguments arguments) throws Exception { + return new Object[] { this.array != null ? this.array.length : 0 }; + } + + @Callback(doc="function():table -- Returns ALL the stack in the this.array. Memory intensive.") + public Object[] getAll(Context context, Arguments arguments) throws Exception { + TreeMap map = new TreeMap(); + for (int i=0; i 0 时,信号可以穿透方块,并且强度将衰减到信号强度 - 方块硬度,空气硬度是1,当强度下降到0时,目标将不会收到信号.通常你需要保证发送和接受之间的连线是净空的. \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/doc/zh_CN/item/worldSensorCard.md b/src/main/resources/assets/opencomputers/doc/zh_CN/item/worldSensorCard.md new file mode 100644 index 000000000..6707c0981 --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/zh_CN/item/worldSensorCard.md @@ -0,0 +1,5 @@ +# World Sensor Card + +![To boldly go...](oredict:oc:worldSensorCard) + +世界传感器卡允许读取大气,重力等世界信息,通常用于加入了星系mod的情况,用于调节在空间内工作的机器人 \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/doc/zh_CN/item/wrench.md b/src/main/resources/assets/opencomputers/doc/zh_CN/item/wrench.md new file mode 100644 index 000000000..accac8b1d --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/zh_CN/item/wrench.md @@ -0,0 +1,5 @@ +# Scrench + +![Made in Swiss.](oredict:oc:wrench) + +扳手 => 融合了螺丝刀和普通扳手的功能,可以拿来旋转方块 \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/lang/ru_RU.lang b/src/main/resources/assets/opencomputers/lang/ru_RU.lang index 22a24f006..879057e69 100644 --- a/src/main/resources/assets/opencomputers/lang/ru_RU.lang +++ b/src/main/resources/assets/opencomputers/lang/ru_RU.lang @@ -340,7 +340,7 @@ oc:tooltip.redstonecard.WirelessSV=Мод §fWireless Redstone (SlimeVoid)§7 § oc:tooltip.redstonecard=Позволяет принимать и излучать сигналы красного камня вокруг компьютера или робота. oc:tooltip.relay=Позволяет соединять различные сети между собой. Передаются только сообщения, компоненты между сетями недоступны. Используйте его для разделения сетей с возможностью пересылать сообщения между ними. oc:tooltip.robot=В отличие от компьютеров, роботы могут передвигаться и взаимодействовать с миром, как игрок.[nl] §cНе могут взаимодействовать с внешними компонентами.§7 -# the underscore makes sure this isn't hidden with the rest of the tooltip. +# The underscore makes sure this isn't hidden with the rest of the tooltip. oc:tooltip.robot_level=§fУровень§7: §a%s§7. oc:tooltip.robot_storedenergy=§fНакопленная энергия§7: §a%s§7. oc:tooltip.screen=Отображает текст, передаваемый видеокартой.[nl] Максимальное разрешение: §f%sx%s§7[nl] Максимальная глубина цвета: §f%s§7 @@ -371,6 +371,9 @@ oc:tooltip.upgradehover=Данное улучшение позволяет ро oc:tooltip.upgradeinventory=Это улучшение даёт место в инвентаре для робота. Без него, роботы не смогут хранить предметы внутри. oc:tooltip.upgradeinventorycontroller=Это улучшение позволяет роботу контролировать взаимодействие с внешними инвентарями и позволяет ему менять свой экипированный инструмент предметом из его инвентаря. oc:tooltip.upgradeleash=Позволяет некоторым устройствам, таким как дроны, цеплять животных на поводок. Много животных, очень. +oc:tooltip.upgrademf=Позволяет адаптерам взаимодействовать с блоками на удалении от них. +oc:tooltip.upgrademf.Linked=§fСоединение установлено§7 +oc:tooltip.upgrademf.Unlinked=§fНет соединения§7 oc:tooltip.upgradenavigation=Позволяет определять положение и ориентацию робота. Положение определяется относительно центра карты, использованной в крафте улучшения. oc:tooltip.upgradepiston=Позволяет двигать блоки, также как и поршни. §lНе§7 может двигать животных, совсем. oc:tooltip.upgradesign=Позволяет читать и писать текст на табличках. diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/edit.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/edit.lua index 3fae5aeef..55860887e 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/edit.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/edit.lua @@ -684,4 +684,4 @@ while running do end term.clear() -term.setCursorBlink(false) +term.setCursorBlink(true) diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/sh.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/sh.lua index 9bb706eee..01f627e4c 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/sh.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/sh.lua @@ -4,15 +4,12 @@ local tty = require("tty") local text = require("text") local sh = require("sh") -local input = table.pack(...) -local args = shell.parse(select(3,table.unpack(input))) -if input[2] then - table.insert(args, 1, input[2]) -end +local args, options = shell.parse(...) shell.prime() -local update_gpu = io.output().tty -local interactive = io.input().tty +local update_gpu = io.output().tty and not options.c +local needs_profile = io.input().tty +local input_handler = {hint = sh.hintHandler} if #args == 0 then while true do @@ -20,15 +17,13 @@ if #args == 0 then while not tty.isAvailable() do event.pull("term_available") end - if interactive == true then -- first time run AND interactive - interactive = 0 - tty.setReadHandler({hint = sh.hintHandler}) + if needs_profile then -- first time run AND interactive + needs_profile = nil dofile("/etc/profile.lua") end io.write(sh.expand(os.getenv("PS1") or "$ ")) - tty.setCursorBlink(true) end - local command = io.read() + local command = tty:read(input_handler) if command then command = text.trim(command) if command == "exit" then @@ -39,7 +34,7 @@ if #args == 0 then io.stderr:write((reason and tostring(reason) or "unknown error") .. "\n") end end - elseif not interactive then + else return -- eof end if update_gpu and tty.getCursor() > 1 then diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/source.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/source.lua index 2b1cc20ec..8286ad1ed 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/source.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/source.lua @@ -24,9 +24,6 @@ local source_data = process.list[source_proc].data source_data.aliases = current_data.aliases -- hacks to propogate sub shell env changes source_data.vars = current_data.vars source_data.io[0] = file -- set stdin to the file -if options.q then - source_data.io[1] = {tty=false,write=function()end} -- set stdin to the file -end -process.internal.continue(source_proc) +process.internal.continue(source_proc, "-c") file:close() -- should have closed when the process closed, but just to be sure diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/tree.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/tree.lua new file mode 100644 index 000000000..e831cee04 --- /dev/null +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/tree.lua @@ -0,0 +1,321 @@ +local shell = require("shell") +local fs = require("filesystem") +local tx = require("transforms") +local text = require("text") + +local args, opts = shell.parse(...) + +local function die(...) + io.stderr:write(...) + os.exit(1) +end + +do -- handle cli + if opts.help then + print([[Usage: tree [OPTION]... [FILE]... + -a, --all do not ignore entries starting with . + --full-time with -l, print time in full iso format + -h, --human-readable with -l, print human readable sizes + --si likewise, but use powers of 1000 not 1024 + --level=LEVEL descend only LEVEL directories deep + --color=WHEN WHEN can be + auto - colorize output only if writing to a tty, + always - always colorize output, + never - never colorize output; (default: auto) + -l use a long listing format + -f print the full path prefix for each file + -i do not print indentation lines + -p append "/" indicator to directories + -Q, --quote quote filenames with double quotes + -r, --reverse reverse order while sorting + -S sort by file size + -t sort by modification type, newest first + -X sort alphabetically by entry extension + -C do not count files and directories + -R count root directories like other files + --help print this help and exit]]) + return 0 + end + + if #args == 0 then + table.insert(args, ".") + end + + opts.level = tonumber(opts.level) or math.huge + if opts.level < 1 then + die("Invalid level, must be greater than 0") + end + + opts.color = opts.color or "auto" + if opts.color == "auto" then + opts.color = io.stdout.tty and "always" or "never" + end + + if opts.color ~= "always" and opts.color ~= "never" then + die("Invalid value for --color=WHEN option; WHEN should be auto, always or never") + end +end + +local function peekable(iterator, state, var1) + local nextItem = {iterator(state, var1)} + + return setmetatable({ + peek = function() + return table.unpack(nextItem) + end + }, { + __call = coroutine.wrap(function() + while true do + local item = nextItem + nextItem = {iterator(state, nextItem[1])} + coroutine.yield(table.unpack(item)) + if nextItem[1] == nil then break end + end + end) + }) +end + +local function filter(entry) + return opts.a or entry:sub(1, 1) ~= "." +end + +local function stat(path) + local st = {} + st.path = path + st.name = fs.name(path) or "/" + st.sortName = st.name:gsub("^%.","") + st.time = fs.lastModified(path) + st.isLink = fs.isLink(path) + st.isDirectory = fs.isDirectory(path) + st.size = st.isLink and 0 or fs.size(path) + st.extension = st.name:match("(%.[^.]+)$") or "" + st.fs = fs.get(path) + return st +end + +local colorize +if opts.color == "always" then + -- from /lib/core/full_ls.lua + local colors = tx.foreach(text.split(os.getenv("LS_COLORS") or "", {":"}, true), function(e) + local parts = text.split(e, {"="}, true) + return parts[2], parts[1] + end) + + function colorize(stat) + return stat.isLink and colors.ln or + stat.isDirectory and colors.di or + colors["*" .. stat.extension] or + colors.fi + end +end + +local function list(path) + return coroutine.wrap(function() + local l = {} + for entry in fs.list(path) do + if filter(entry) then + table.insert(l, stat(fs.concat(path, entry))) + end + end + + if opts.S then + table.sort(l, function(a, b) + return a.size < b.size + end) + elseif opts.t then + table.sort(l, function(a, b) + return a.time < b.time + end) + elseif opts.X then + table.sort(l, function(a, b) + return a.extension < b.extension + end) + else + table.sort(l, function(a, b) + return a.sortName < b.sortName + end) + end + + for i = opts.r and #l or 1, opts.r and 1 or #l, opts.r and -1 or 1 do + coroutine.yield(l[i]) + end + end) +end + +local function digRoot(rootPath) + coroutine.yield(stat(rootPath), {}) + + if not fs.isDirectory(rootPath) then + return + end + local iterStack = {peekable(list(rootPath))} + local pathStack = {rootPath} + local levelStack = {not not iterStack[#iterStack]:peek()} + + + repeat + local entry = iterStack[#iterStack]() + + if entry then + levelStack[#levelStack] = not not iterStack[#iterStack]:peek() + + local path = fs.concat(fs.concat(table.unpack(pathStack)), entry.name) + + coroutine.yield(entry, levelStack) + + if entry.isDirectory and opts.level > #levelStack then + table.insert(iterStack, peekable(list(path))) + table.insert(pathStack, entry.name) + table.insert(levelStack, not not iterStack[#iterStack]:peek()) + end + else + table.remove(iterStack) + table.remove(pathStack) + table.remove(levelStack) + end + until #iterStack == 0 +end + +local function dig(roots) + return coroutine.wrap(function() + for _, root in ipairs(roots) do + digRoot(root) + end + end) +end + +local function nod(n) -- from /lib/core/full_ls.lua + return n and (tostring(n):gsub("(%.[0-9]+)0+$","%1")) or "0" +end + +local function formatFSize(size) -- from /lib/core/full_ls.lua + if not opts.h and not opts["human-readable"] and not opts.si then + return tostring(size) + end + + local sizes = {"", "K", "M", "G"} + local unit = 1 + local power = opts.si and 1000 or 1024 + + while size > power and unit < #sizes do + unit = unit + 1 + size = size / power + end + + return nod(math.floor(size*10)/10)..sizes[unit] +end + +local function pad(txt) -- from /lib/core/full_ls.lua + txt = tostring(txt) + return #txt >= 2 and txt or "0" .. txt +end + +local function formatTime(epochms) -- from /lib/core/full_ls.lua + local month_names = {"January","February","March","April","May","June", + "July","August","September","October","November","December"} + + if epochms == 0 then return "" end + + local d = os.date("*t", epochms) + local day, hour, min, sec = nod(d.day), pad(nod(d.hour)), pad(nod(d.min)), pad(nod(d.sec)) + + if opts["full-time"] then + return string.format("%s-%s-%s %s:%s:%s ", d.year, pad(nod(d.month)), pad(day), hour, min, sec) + else + return string.format("%s %+2s %+2s:%+2s ", month_names[d.month]:sub(1,3), day, hour, pad(min)) + end +end + +local function writeEntry(entry, levelStack) + for i, hasNext in ipairs(levelStack) do + if opts.i then break end + + if i == #levelStack then + if hasNext then + io.write("├── ") + else + io.write("└── ") + end + else + if hasNext then + io.write("│   ") + else + io.write(" ") + end + end + end + + if opts.l then + io.write("[") + + io.write(entry.isDirectory and "d" or entry.isLink and "l" or "f", "-") + io.write("r", entry.fs.isReadOnly() and "-" or "w", " ") + + io.write(formatFSize(entry.size), " ") + + io.write(formatTime(entry.time)) + io.write("] ") + end + + if opts.Q then io.write('"') end + + if opts.color == "always" then + io.write("\27[" .. colorize(entry) .. "m") + end + + if opts.f then + io.write(entry.path) + else + io.write(entry.name) + end + + if opts.color == "always" then + io.write("\27[0m") + end + + if opts.p and entry.isDirectory then + io.write("/") + end + + if opts.Q then io.write('"') end + io.write("\n") +end + +local function writeCount(dirs, files) + io.write("\n") + io.write(dirs, " director", dirs == 1 and "y" or "ies") + io.write(", ") + io.write(files, " file", files == 1 and "" or "s") + io.write("\n") +end + +local dirs, files = 0, 0 + +local roots = {} +for _, arg in ipairs(args) do + local path = shell.resolve(arg) + local real, reason = fs.realPath(path) + if not real then + die("cannot access ", path, ": ", reason or "unknown error") + elseif not fs.exists(path) then + die("cannot access ", path, ":", "No such file or directory") + else + table.insert(roots, real) + end +end + +for entry, levelStack in dig(roots) do + if opts.R or #levelStack > 0 then + if entry.isDirectory then + dirs = dirs + 1 + else + files = files + 1 + end + end + writeEntry(entry, levelStack) +end + +if not opts.C then + writeCount(dirs, files) +end + diff --git a/src/main/resources/assets/opencomputers/loot/openos/etc/profile.lua b/src/main/resources/assets/opencomputers/loot/openos/etc/profile.lua index 8f8fecb2d..76c7ecca3 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/etc/profile.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/etc/profile.lua @@ -3,8 +3,11 @@ local tty = require("tty") local fs = require("filesystem") if tty.isAvailable() then - tty:write("\27[40m\27[37m") - tty.clear() + if io.stdout.tty then + io.write("\27[40m\27[37m") + tty.clear() + end + tty.setCursorBlink(true) end dofile("/etc/motd") @@ -31,11 +34,11 @@ os.setenv("IFS", " ") os.setenv("MANPATH", "/usr/man:.") os.setenv("PAGER", "/bin/more") os.setenv("PS1", "\27[40m\27[31m$HOSTNAME$HOSTNAME_SEPARATOR$PWD # \27[37m") -os.setenv("LS_COLORS", "{FILE=0xFFFFFF,DIR=0x66CCFF,LINK=0xFFAA00,['*.lua']=0x00FF00}") +os.setenv("LS_COLORS", "di=0;36:fi=0:ln=0;33:*.lua=0;32") shell.setWorkingDirectory(os.getenv("HOME")) local home_shrc = shell.resolve(".shrc") if fs.exists(home_shrc) then - loadfile(shell.resolve("source", "lua"))(home_shrc, "-q") + loadfile(shell.resolve("source", "lua"))(home_shrc) end diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/core/devfs/01_hw.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/core/devfs/01_hw.lua index 50e4a3147..8c8b8e231 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/core/devfs/01_hw.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/core/devfs/01_hw.lua @@ -40,8 +40,8 @@ end function adapter_api.create_toggle(read, write, switch) return { - read = function() return tostring(read()) end, - write = function(value) + read = read and function() return tostring(read()) end, + write = write and function(value) value = text.trim(tostring(value)) local on = value == "1" or value == "true" local off = value == "0" or value == "false" diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/core/full_ls.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/core/full_ls.lua index 5e7eb6bec..57e178153 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/core/full_ls.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/core/full_ls.lua @@ -2,6 +2,8 @@ local fs = require("filesystem") local shell = require("shell") local tty = require("tty") local unicode = require("unicode") +local tx = require("transforms") +local text = require("text") local dirsArg, ops = shell.parse(...) @@ -32,7 +34,6 @@ if #dirsArg == 0 then end local ec = 0 -local gpu = tty.gpu() local fOut = tty.isAvailable() and io.output().tty local function perr(msg) io.stderr:write(msg,"\n") ec = 2 end local function stat(names, index) @@ -56,42 +57,30 @@ local function stat(names, index) return info end local function toArray(i) local r={} for n in i do r[#r+1]=n end return r end -local restore_color = function() end local set_color = function() end -local prev_color -local function colorize() return prev_color end +local function colorize() return end if fOut and not ops["no-color"] then - local LSC = os.getenv("LS_COLORS") - if type(LSC) == "string" then - LSC = require("serialization").unserialize(LSC) + local LSC = tx.foreach(text.split(os.getenv("LS_COLORS") or "", {":"}, true), function(e) + local parts = text.split(e, {"="}, true) + return parts[2], parts[1] + end) + colorize = function(info) + return + info.isLink and LSC.ln or + info.isDir and LSC.di or + LSC['*'..info.ext] or + LSC.fi end - if not LSC then - perr("ls: unparsable value for LS_COLORS environment variable") - else - prev_color = gpu.getForeground() - restore_color = function() gpu.setForeground(prev_color) end - colorize = function(info) - return - info.isLink and LSC.LINK or - info.isDir and LSC.DIR or - LSC['*'..info.ext] or - LSC.FILE or - prev_color - end - set_color=function(c) - if gpu.getForeground() ~= c then - io.stdout:flush() - gpu.setForeground(c) - end - end + set_color=function(c) + io.write(string.char(0x1b), "[", c or "", "m") end end local msft={reports=0,proxies={}} function msft.report(files, dirs, used, proxy) local free = proxy.spaceTotal() - proxy.spaceUsed() - restore_color() - local pattern = "%5i File(s) %11i bytes\n%5i Dir(s) %11s bytes free\n" - io.write(string.format(pattern, files, used, dirs, tostring(free))) + set_color() + local pattern = "%5i File(s) %s bytes\n%5i Dir(s) %11s bytes free\n" + io.write(string.format(pattern, files, tostring(used), dirs, tostring(free))) end function msft.tail(names) local fsproxy = fs.get(names.path) @@ -123,7 +112,7 @@ function msft.final() for proxy,report in pairs(msft.proxies) do table.insert(groups, {proxy=proxy,report=report}) end - restore_color() + set_color() print("Total Files Listed:") for _,pair in ipairs(groups) do local proxy, report = pair.proxy, pair.report @@ -263,7 +252,7 @@ local function display(names) local format = "%s-r%s %+"..tostring(max_size_width).."s %"..tostring(max_date_width).."s" local meta = string.format(format, file_type, write_mode, size, modDate) local item = info.name..link_target - return {{color = prev_color, name = meta}, {color = colorize(info), name = item}} + return {{name = meta}, {color = colorize(info), name = item}} end elseif ops["1"] or not fOut then lines.n = #names @@ -332,7 +321,7 @@ local header = function() end if #dirsArg > 1 or ops.R then header = function(path) if not first_display then print() end - restore_color() + set_color() io.write(path,":\n") end end @@ -366,11 +355,20 @@ for _,dir in ipairs(dirsArg) do table.insert(file_set, dir) end end + io.output():setvbuf("line") -if #file_set > 0 then display(sort(file_set)) end -displayDirList(dir_set) -msft.final() + +local ok, msg = pcall(function() + if #file_set > 0 then display(sort(file_set)) end + displayDirList(dir_set) + msft.final() +end) + io.output():flush() io.output():setvbuf("no") -restore_color() +set_color() + +assert(ok, msg) + return ec + diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/core/lua_shell.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/core/lua_shell.lua index 82f4dbe32..ad7997a63 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/core/lua_shell.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/core/lua_shell.lua @@ -68,7 +68,7 @@ local function findKeys(t, r, prefix, name) end end -tty.setReadHandler({hint = function(line, index) +local read_handler = {hint = function(line, index) line = (line or "") local tail = line:sub(index) line = line:sub(1, index - 1) @@ -85,7 +85,7 @@ tty.setReadHandler({hint = function(line, index) table.insert(hints, key .. tail) end return hints -end}) +end} io.write("\27[37m".._VERSION .. " Copyright (C) 1994-2017 Lua.org, PUC-Rio\n") io.write("\27[33mEnter a statement and hit enter to evaluate it.\n") @@ -94,7 +94,7 @@ io.write("Press Ctrl+D to exit the interpreter.\n\27[37m") while tty.isAvailable() do io.write(env._PROMPT) - local command = io.read() + local command = tty:read(read_handler) if not command then -- eof return end diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua index 2171f4279..2d6d7740d 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/filesystem.lua @@ -24,7 +24,6 @@ end local function saveConfig() local root = filesystem.get("/") if root and not root.isReadOnly() then - filesystem.makeDirectory("/etc") local f = filesystem.open("/etc/filesystem.cfg", "w") if f then f:write("autorun="..tostring(isAutorunEnabled)) diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua index 207c681c0..3ce1df9ff 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua @@ -194,9 +194,6 @@ function term.write(value, wrap) end function term.read(history, dobreak, hint, pwchar, filter) - if not io.stdin.tty then - return io.read("*L") - end history = history or {} local handler = history handler.hint = handler.hint or hint diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/tty.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/tty.lua index e54531f24..131975a8a 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/tty.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/tty.lua @@ -3,7 +3,6 @@ local event = require("event") local kb = require("keyboard") local component = require("component") local computer = require("computer") -local process = require("process") local keys = kb.keys local tty = {} @@ -19,11 +18,6 @@ tty.window = tty.internal = {} -function tty.setReadHandler(handler) - checkArg(1, handler, "table") - process.info().data.handler = handler -end - function tty.key_down_handler(handler, cursor, char, code) local data = cursor.data local c = false @@ -267,16 +261,18 @@ function tty.internal.build_vertical_reader() } end --- read n bytes, n is unused +-- PLEASE do not use this method directly, use io.read or tty.read function tty.read(_, handler, cursor) checkArg(1, handler, "table", "number") checkArg(2, cursor, "table", "nil") - if type(handler) == "number" then - -- standard read as a stream, asking for n bytes - handler = process.info().data.handler or {} + if not io.stdin.tty then + return io.stdin:readLine(false) end + if type(handler) ~= "table" then + handler = {} + end handler.index = 0 cursor = cursor or tty.internal.build_vertical_reader() @@ -324,7 +320,11 @@ function tty.setCursor(x, y) window.x, window.y = x, y end +-- PLEASE do not use this method directly, use io.write or term.write function tty.write(_, value) + if not io.stdout.tty then + return io.write(value) + end local gpu = tty.gpu() if not gpu then return @@ -352,7 +352,8 @@ function tty.write(_, value) value = window.ansi_escape:sub(5) end for _,catt in ipairs(color_attributes) do - local colors = {0x0,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00ffff,0xffffff} + -- B6 is closer to cyan in 4 bit color + local colors = {0x0,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00B6ff,0xffffff} catt = catt - 29 local method = "setForeground" if catt > 10 then diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/vt100.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/vt100.lua index f32488909..4e6111b50 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/vt100.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/vt100.lua @@ -1,3 +1,4 @@ +local text = require("text") local vt100 = {} -- runs patterns on ansi until failure @@ -25,15 +26,26 @@ local rules = {} -- [%d+;%d+;..%d+m rules[{"%[", "[%d;]*", "m"}] = function(_, _, number_text) local numbers = {} - number_text:gsub("[^;]*", function(num) - local n = tonumber(num) or 0 - if n == 0 then + -- prefix and suffix ; act as reset + -- e.g. \27[41;m is actually 41 followed by a reset + number_text = ";" .. number_text:gsub("^;$","") .. ";" + local parts = text.split(number_text, {";"}) + local last_was_break + for _,part in ipairs(parts) do + local num = tonumber(part) + if not num then + num = last_was_break and 0 + last_was_break = true + else + last_was_break = false + end + if num == 0 then numbers[#numbers + 1] = 40 numbers[#numbers + 1] = 37 - else - numbers[#numbers + 1] = n + elseif num then + numbers[#numbers + 1] = num end - end) + end return numbers end diff --git a/src/main/resources/assets/opencomputers/models/block/adapter.json b/src/main/resources/assets/opencomputers/models/block/adapter.json index a20ea7f23..a535714b8 100644 --- a/src/main/resources/assets/opencomputers/models/block/adapter.json +++ b/src/main/resources/assets/opencomputers/models/block/adapter.json @@ -1,7 +1,7 @@ { "parent": "block/cube_bottom_top", "textures": { - "bottom": "opencomputers:blocks/generic_top", + "bottom": "opencomputers:blocks/adapter_top", "top": "opencomputers:blocks/adapter_top", "side": "opencomputers:blocks/adapter_side" } diff --git a/src/main/resources/assets/opencomputers/robot.names b/src/main/resources/assets/opencomputers/robot.names index 27047dffa..1635f27cc 100644 --- a/src/main/resources/assets/opencomputers/robot.names +++ b/src/main/resources/assets/opencomputers/robot.names @@ -88,6 +88,7 @@ Robby # Forbidden Planet Roomba # Under your couch... wait. Rosie # The Jetsons Shakey # The first general-purpose mobile robot that could reason about its actions. +SHODAN # System Shock Skynet # Terminator Space Core # Portal SpiritedDusty # Contributor diff --git a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala index 07ad82e7a..365577fe4 100644 --- a/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala +++ b/src/main/scala/li/cil/oc/client/renderer/markdown/segment/BasicTextSegment.scala @@ -1,7 +1,6 @@ package li.cil.oc.client.renderer.markdown.segment -import li.cil.oc.client.renderer.markdown.Document -import li.cil.oc.client.renderer.markdown.MarkupFormat +import li.cil.oc.client.renderer.markdown.{Document, MarkupFormat} import net.minecraft.client.gui.FontRenderer trait BasicTextSegment extends Segment { @@ -58,11 +57,21 @@ trait BasicTextSegment extends Segment { while (pos < s.length) { pos += 1 val width = stringWidth(s.take(pos), renderer) - if (width >= maxWidth) { - if (lastBreak > 0 || fullWidth <= maxLineWidth || s.exists(breaks.contains)) - if (maxWidth == maxLineWidth && fullWidth == maxLineWidth && !s.exists(breaks.contains)) return s.length - else return lastBreak + 1 - else return pos - 1 + val exceedsLineLength = width >= maxWidth + if (exceedsLineLength) { + val mayUseFullLine = maxWidth == maxLineWidth + val canFitInLine = fullWidth <= maxLineWidth + val matchesFullLine = fullWidth == maxLineWidth + if (lastBreak >= 0) { + return lastBreak + 1 // Can do a soft split. + } + if (mayUseFullLine && matchesFullLine) { + return s.length // Special case for exact match. + } + if (canFitInLine && !mayUseFullLine) { + return 0 // Wrap line, use next line. + } + return pos - 1 // Gotta split hard. } if (pos < s.length && breaks.contains(s.charAt(pos))) lastBreak = pos } diff --git a/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala b/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala index cad8fd44e..adac32777 100644 --- a/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala +++ b/src/main/scala/li/cil/oc/common/asm/ClassTransformer.scala @@ -25,7 +25,7 @@ object ObfNames { final val Method_recreateLeash = Array("recreateLeash", "func_110165_bF", "da") final val Method_recreateLeashDesc = Array("()V") final val Method_renderLeash = Array("renderLeash", "func_110827_b", "b") - final val Method_renderLeashDesc = Array("(Lsg;DDDFF)V", "(Lnet/minecraft/entity/EntityLiving;DDDFF)V") + final val Method_renderLeashDesc = Array("(L"+Class_EntityLiving(1)+";DDDFF)V", "(Lnet/minecraft/entity/EntityLiving;DDDFF)V") final val Method_validate = Array("validate", "func_145829_t") final val Method_invalidate = Array("invalidate", "func_145843_s") final val Method_onChunkUnload = Array("onChunkUnload", "func_76623_d") diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala index 4767921f7..ee46da2f1 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala @@ -4,10 +4,12 @@ import li.cil.oc.Settings import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context +import li.cil.oc.api.prefab.ItemStackArrayValue import li.cil.oc.server.component.result -import li.cil.oc.util.DatabaseAccess +import li.cil.oc.util.{BlockPosition, DatabaseAccess, InventoryUtils} +import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedArguments._ -import li.cil.oc.util.InventoryUtils +import net.minecraft.block.Block import li.cil.oc.util.StackOption import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing @@ -77,6 +79,36 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ } else result(Unit, "not enabled in config") + @Callback(doc = """function(side:number):userdata -- Get a description of all stacks in the inventory on the specified side of the device.""") + def getAllStacks(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) { + val facing = checkSideForAction(args, 0) + withInventory(facing, inventory => { + val stacks = new Array[ItemStack](inventory.getSlots) + for(i <- 0 until inventory.getSlots){ + stacks(i) = inventory.getStackInSlot(i) + } + result(new ItemStackArrayValue(stacks)) + }) + } + else result(Unit, "not enabled in config") + + @Callback(doc = """function(side:number):string -- Get the the name of the inventory on the specified side of the device.""") + def getInventoryName(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) { + val facing = checkSideForAction(args, 0) + def blockAt(position: BlockPosition): Option[Block] = position.world match { + case Some(world) if world.blockExists(position) => world.getBlock(position) match { + case block: Block => Some(block) + case _ => None + } + case _ => None + } + withInventory(facing, inventory => blockAt(position.offset(facing)) match { + case Some(block) => result(block.getRegistryName) + case _ => result(Unit, "Unknown") + }) + } + else result(Unit, "not enabled in config") + @Callback(doc = """function(side:number, slot:number, dbAddress:string, dbSlot:number):boolean -- Store an item stack description in the specified slot of the database with the specified address.""") def store(context: Context, args: Arguments): Array[AnyRef] = { val facing = checkSideForAction(args, 0) diff --git a/src/main/scala/li/cil/oc/server/machine/luac/UnicodeAPI.scala b/src/main/scala/li/cil/oc/server/machine/luac/UnicodeAPI.scala index 0be3f1ead..c327815c4 100644 --- a/src/main/scala/li/cil/oc/server/machine/luac/UnicodeAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luac/UnicodeAPI.scala @@ -81,7 +81,7 @@ class UnicodeAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { var width = 0 var end = 0 while (width < count) { - width += FontUtils.wcwidth(value(end)) + width += math.max(1, FontUtils.wcwidth(value(end))) end += 1 } if (end > 1) lua.pushString(value.substring(0, end - 1)) diff --git a/src/main/scala/li/cil/oc/server/machine/luac/UserdataAPI.scala b/src/main/scala/li/cil/oc/server/machine/luac/UserdataAPI.scala index 168a19da1..3d24fe65e 100644 --- a/src/main/scala/li/cil/oc/server/machine/luac/UserdataAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luac/UserdataAPI.scala @@ -8,6 +8,7 @@ import java.io.DataOutputStream import li.cil.oc.OpenComputers import li.cil.oc.api.Persistable import li.cil.oc.api.machine.Value +import li.cil.oc.server.driver.Registry import li.cil.oc.server.machine.ArgumentsImpl import li.cil.oc.util.ExtendedLuaState.extendLuaState import net.minecraft.nbt.CompressedStreamTools @@ -56,7 +57,7 @@ class UserdataAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { lua.pushScalaFunction(lua => { val value = lua.toJavaObjectRaw(1).asInstanceOf[Value] val args = lua.toSimpleJavaObjects(2) - owner.invoke(() => Array(value.apply(machine, new ArgumentsImpl(args)))) + owner.invoke(() => Registry.convert(Array(value.apply(machine, new ArgumentsImpl(args))))) }) lua.setField(-2, "apply") @@ -73,7 +74,7 @@ class UserdataAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) { lua.pushScalaFunction(lua => { val value = lua.toJavaObjectRaw(1).asInstanceOf[Value] val args = lua.toSimpleJavaObjects(2) - owner.invoke(() => value.call(machine, new ArgumentsImpl(args))) + owner.invoke(() => Registry.convert(value.call(machine, new ArgumentsImpl(args)))) }) lua.setField(-2, "call") diff --git a/src/main/scala/li/cil/oc/server/machine/luaj/UnicodeAPI.scala b/src/main/scala/li/cil/oc/server/machine/luaj/UnicodeAPI.scala index b791210e1..2f008bddb 100644 --- a/src/main/scala/li/cil/oc/server/machine/luaj/UnicodeAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luaj/UnicodeAPI.scala @@ -53,7 +53,7 @@ class UnicodeAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { var width = 0 var end = 0 while (width < count) { - width += FontUtils.wcwidth(value(end)) + width += math.max(1, FontUtils.wcwidth(value(end))) end += 1 } if (end > 1) LuaValue.valueOf(value.substring(0, end - 1)) diff --git a/src/main/scala/li/cil/oc/server/machine/luaj/UserdataAPI.scala b/src/main/scala/li/cil/oc/server/machine/luaj/UserdataAPI.scala index 6ada183b2..336fc4eea 100644 --- a/src/main/scala/li/cil/oc/server/machine/luaj/UserdataAPI.scala +++ b/src/main/scala/li/cil/oc/server/machine/luaj/UserdataAPI.scala @@ -2,6 +2,7 @@ package li.cil.oc.server.machine.luaj import li.cil.oc.OpenComputers import li.cil.oc.api.machine.Value +import li.cil.oc.server.driver.Registry import li.cil.oc.server.machine.ArgumentsImpl import li.cil.oc.util.ScalaClosure._ import li.cil.repack.org.luaj.vm2.LuaValue @@ -16,7 +17,7 @@ class UserdataAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { userdata.set("apply", (args: Varargs) => { val value = args.checkuserdata(1, classOf[Value]).asInstanceOf[Value] val params = toSimpleJavaObjects(args, 2) - owner.invoke(() => Array(value.apply(machine, new ArgumentsImpl(params)))) + owner.invoke(() => Registry.convert(Array(value.apply(machine, new ArgumentsImpl(params))))) }) userdata.set("unapply", (args: Varargs) => { @@ -31,7 +32,7 @@ class UserdataAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { userdata.set("call", (args: Varargs) => { val value = args.checkuserdata(1, classOf[Value]).asInstanceOf[Value] val params = toSimpleJavaObjects(args, 2) - owner.invoke(() => value.call(machine, new ArgumentsImpl(params))) + owner.invoke(() => Registry.convert(value.call(machine, new ArgumentsImpl(params)))) }) userdata.set("dispose", (args: Varargs) => {