Лидеры
Популярный контент
Показан контент с высокой репутацией 16.07.2020 во всех областях
-
5 балловВнутри песочницы coroutine.yield переопределён: yield = function(...) -- custom yield part for bubbling sysyields return coroutine.yield(nil, ...) end Также переопределён и coroutine.resume. resume = function(co, ...) -- custom resume part for bubbling sysyields checkArg(1, co, "thread") local args = table.pack(...) while true do -- for consecutive sysyields debug.sethook(co, checkDeadline, "", hookInterval) local result = table.pack( coroutine.resume(co, table.unpack(args, 1, args.n))) debug.sethook(co) -- avoid gc issues checkDeadline() if result[1] then -- success: (true, sysval?, ...?) if coroutine.status(co) == "dead" then -- return: (true, ...) return true, table.unpack(result, 2, result.n) elseif result[2] ~= nil then -- yield: (true, sysval) args = table.pack(coroutine.yield(result[2])) else -- yield: (true, nil, ...) return true, table.unpack(result, 3, result.n) end else -- error: result = (false, string) return false, result[2] end end end Работает это так: Если корутина вернула true, nil, ... — отдать true, ... (поэтому внутри песочницы разница между обычными и переопределёнными функциями не видна). Если корутина йелднулась без нила в начале, то это "системный вызов". Потому что доступ к непереопределённой функции coroutine.yield есть только внутри machine.lua. В таком случае йелдится и текущая корутина вверх по цепочке. EEPROM запускается в корутине. Если корутина эта йелдится, случается следующее: yield(false) — это выключить компьютер; yield(true) — ребутнуть его; yield(n), где type(n) == "number", — спать n секунд; yield(f), где type(f) == "function", — это вызвать непрямую функцию. yield с любым другим аргументом — спать до скончания века. Дополнительно обрабатывается умирание корутины: return посреди еепрома — это error("computer halted", 0); другие ошибки прокидываются. А теперь смотрим на наш вызов. В EEPROM вызвана coroutine.yield(0). Эта функция переопределена, чтобы вызвать нативный coroutine.yield(nil, 0). Корутина тогда йелдится и отдаёт nil, 0. В списке выше это пункт 3.5. Компьютер уйдёт в вечный сон. Ну, конечно, я преувеличиваю. Компьютер спит до момента получения сигнала и, получив, продолжит работу. Но вообще, незачем звать coroutine.yield напрямую. Есть computer.pullSignal, computer.shutdown, component.invoke(addr, nonDirectMethod, ...).
-
5 балловОтважно постим мимо Программы новичков Наверняка за такое долгое время развития экосистемы OpenComputers кто-то уже писал свои обработчики аргументов. Я даже видел какую-то на репе hpm (помянем). Для истории: https://gitlab.com/oc-programs/libxargs/raw/master/libxargs.lua Но в основном всех устраивает shell.parse(...). Ну а меня нет. Установка Pastebin: https://pastebin.com/nSgXWHtp Для ленивых: # pastebin get nSgXWHtp /usr/lib/parg.lua На всякий случай: https://gist.github.com/IS2511/96847fe185278b457505218b1c141f9d Органический продукт! Разработан полностью на ocelot-desktop! API parg.parse(a: table): table: Принимает {...}, возвращает таблицу аргументов. Alias: parg(a: table): table. parg.register(argument: string or table, argType: string, callback: function): nil: В argument название аргумента или список названий одного и того же аргумента (Например {"timeout", "t"}). В argType либо "flag", либо "value". В callback функция с 1 аргументом, это будет либо кол-во флагов, либо значение. Последний аргумент необязательный. parg.unregister(argument: string or table, clearSame: boolean): nil: В argument название аргумента или список названий аргументов (Например {"timeout", "verbose"}). Если clearSame = true, то родственные аргументы также будут удалены. Последний аргумент необязательный, по умолчанию false. Я не знаю зачем эта функция, она просто есть. Базовое использование Механика библиотеки схожа c shell.parse. Для быстроты приведу примеры. Программа для тестов будет такая (далее prog.lua): local ser = require("serialization") local parg = require("parg") local arg = parg({...}) -- same as parg.parse({...}) print(ser.serialize(arg)) Попробуем вызвать с набором разных аргументов: /home # prog test1 test2=test3 --test4 --test5=test6 -test7 -89=10 {"test1","test2=test3",[0]="/home/prog.lua",["9"]="10",test5="test6",["8"]=1,["7"]=1,t=2,s=1,e=1,test4=1} Тут в принципе есть все основные варианты аргументов и их поведение. Самые простые аргументы типа "test1" и "test2=test3" далее не будут рассматриваться. Как можно заметить появился также аргумент [0]="/home/prog.lua", это путь к файлу, который вызвал parg(), бывает иногда удобно. Этот аргумент так же далее не будет рассматриваться. (TODO: Есть мысли, что вызов debug.getinfo(3, "S") самый затратный из всей либы. Так ли это?) Регистрация аргуметов Типы В библиотеке есть 2 типа аргументов: "flag" и "value". Первый всегда number, второй всегда string или nil. По умолчанию (без регистрации аргументов) все аргументы считаются "flag", если не используется =, тогда аргумент считается "value". "flag" в значении имеют количество своих появлений. Например prog -xxx => {x=3}. "value" в значении имеют строку со значением, указанным пользователем. Например prog -x=123, prog --x=123 => {x="123"}; prog --test=123 => {test="123"}. Далее переходим к регистрации типов аргументов. Отредактируем prog.lua: local ser = require("serialization") local parg = require("parg") parg.register({"timeout", "t"}, "value") parg.register({"verbose", "v"}, "flag") local arg = parg({...}) print(ser.serialize(arg)) Теперь некоторые аргументы имеют явный тип, а также родственников (Получается "--timeout" = "-t" = "--t"). Поскольку у "timeout" теперь явно тип "value", аргумент может принимать значения через пробел prog -t 10 => {t="10",verbose=0,v=0,timeout="10"}. Обратим внимание! Отсутсвие "flag" дает 0 в таблице аргументов. "verbose" явно "flag", значит любые = больше не сработают prog -v=abc --verbose=def => {v=2,verbose=2}. Каллбэки Последняя фича - каллбэки. Добавим в prog.lua последние штрихи: local ser = require("serialization") local parg = require("parg") local timeout, verbose parg.register({"timeout", "t"}, "value", function (value) timeout = tonumber(value) or 10 end) parg.register({"verbose", "v"}, "flag", function (count) verbose = count > 0 end) parg({...}) print(ser.serialize({timeout,verbose})) Попробуем. prog => {10,false}; prog -t abc => {10,false}; prog -t 20 -v => {20,true}; prog --verbose => {10,true} Ну вот и все, библиотека работает. TODO: Добавить порядок обработки? Взаимосвязанные каллбэки? Конец Остался только один вопрос. Зачем? Почему у меня не используются регулярки? А нужны ли они? На самом деле я просто забыл о них, не знаю есть ли смысл переделывать. Комментарии и критика приветствуются :з Первый пост, критика по оформлению также велком
-
2 баллаOMA-1.7.10-3.2.0.jar v3.2.0 Добавлено: Метод tell для креативного чатбокса.
-
1 баллСигнал случайно вытащить можем. Поэтому, если важно не терять сигналы, то потребуется написать обработчик. Если пропуск сигналов критичен, то проверка сигналов обязательна в любом случае, т.к. очередь сигналов ограничена и может быть переполнена. yield, скорее всего, нужно вызвать с параметром времени ожидания yield(0), или же ждать сигнала. Как в этом случае обрабатывать само событие, я не знаю, не пробовал.
-
1 баллВыполнение computer.pullSignal(0) обеспечит минимальную уступку времени.
-
1 баллКаждый метод компонента в OpenComputers характеризуется его прямотой: есть прямые методы, а есть непрямые. Не раз в ирке разъяснял разницу. Сейчас расскажу и вам. Предположения: Текущая версия мода — 1.7.5. Вы собирали опенкомпьютер. Вы знаете, кто такой компонент, что у него за методы и как их вызвать. С непрямыми вызовами всё просто. Они уводят компьютер в сон на тик. Всегда, при любом условии, даже в случае ошибки, после вызова непрямого метода компьютер до следующего тика работать не будет. Прямые вызовы такого ограничения не имеют. Один такой вызов может занимать произвольное количество времени. Зависит это от бюджета вызовов. У компьютеров OC есть бюджет вызовов. Это скрытая безразмерная величина. Каждый тик она сбрасывается до определённого значения. Определено оно так: Сначала смотрим на процессор в компьютере. Точнее, на уровень: T1 соответствует 0.5, T2 — 1.0, T3 — 1.5. Затем на каждую из планок памяти. T1 или T1.5 — это 0.5, T2 или T2.5 — 1.0, T3 или T3.5 — 1.5. Получаем несколько чисел. Суммируем, делим на количество — находим тем самым среднее арифметическое, которое и будет максимальным бюджетом вызовов. Практикум: T2 процессор → 1.0 Планка T2.5 → 1.0 Планка T3.5 → 1.5 Бюджет вызовов: (1.0 + 1.0 + 1.5) / 3 ≈ 1.167. Пример второй: Т3 процессор → 1.5 Планки T3.5 → 1.5, 1.5, 1.5 Планка T2.5 → 1.0 Бюджет вызовов: (1.5 + 1.5 + 1.5 + 1.5 + 1.0) / 5 = 1.4. Достаточно. Каждый прямой вызов расходует этот бюджет. По умолчанию — ровно одну тысячную его. Самые последние дев-билды мода делают прямые вызовы по умолчанию абсолютно бесплатными. Когда бюджет уходит в минус, компьютер принудительно спит до следующего тика. Определяет прямоту метода разработчик. Для создания метода в коде мода используется аннотация li.cil.oc.api.machine.Callback. Примерно так (метод hologram.get): @Callback(direct = true, doc = """function(x:number, y:number, z:number):number -- Returns the value for the specified voxel.""") def get(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { ... } Если мы видим здесь direct = true, то это абсолютно точно прямой вызов. Если direct = false или отсутствует, то вызов непрямой. У метода может быть кастомная стоимость вызова. Не 0.001. У дата-карточки такое особенно. Пример (data.inflate): @Callback(direct = true, limit = 4, doc = """function(data:string):string -- Applies inflate decompression to the data.""") def inflate(context: Context, args: Arguments): Array[AnyRef] = { ... } limit = 4 читать как "потребляю 1/4 бюджета при вызове". Для сервера выше это 5 вызовов в тик. Недурно. У видеокарты всё сложно. Вообще, она тоже ограничивает ярость использования через бюджет вызовов. Потому на Т3-комплекте работать будет быстрее. Но количество потребляемого бюджета также зависит и от уровня видеокарточки. Для OC 1.7.5 распределение такое: Операция Стоимость T1 GPU T2 GPU T3 GPU setBackground 1/32 1/64 1/128 setForeground 1/32 1/64 1/128 setPaletteColor 1/2 1/8 1/16 set 1/64 1/128 1/256 copy 1/16 1/32 1/64 fill 1/32 1/64 1/128 Поэтому максимально можно вызвать 384 сета в тик. Чтобы программно определить прямоту методов, есть функция component.methods(addr). Отдаём ей полный адрес компонента, получаем таблицу. В ключах имена методов, в значениях их прямота. Или же можно воспользоваться этой таблицей. Она включает все методы всех компонентов, которые есть в OpenComputers. И наконец, размер бюджета можно сменить в конфиге. Опция budgetCosts занимается именно этим.
-
1 балл
Эта таблица лидеров рассчитана в Москва/GMT+03:00
