ECS
Гуру-
Публикации
533 -
Зарегистрирован
-
Посещение
-
Победитель дней
203
Тип публикации
Блоги
Профили
Форум
Багтрекер
Магазин
Все публикации пользователя ECS
-
Ничего не понял, т.к. исходники из архива работают без ошибок. Судя по скрину, проблема была в том, что b на каком-то этапе становилась nil - вполне вероятно, из-за того, что она глобальна для нескольких файлов приложения, и возникал конфликт Ошибка в либе unicode, иссую на гите создал, должны пофиксить. Вообще, если уж играешь на снапшотах, то стабильности ждать не приходится - на то они и снапшоты Доделать - не, слишком сложно и непонятно, а немного инфы по системе дать могу: 1) При работе с UI и workspace не стоит злоупотреблять слушателями нажатий на клавиши через event.addHandler, т.к. это низкоуровневая фича, предназначенная для обработки событий вне интерфейса. К примеру, для библиотеки keyboard и реализации метода isKeyDown она вполне пригодна, а вот в случае с интерфейсом она дарует лишь попоболь, заставляя вручную вызывать event.removeHandler при любых ошибках или при закрытии приложения. Поэтому, если ты разрабатываешь оконное приложение, интегрирующееся в системный workspace (тот самый, где располагаются ярлыки на раб. столе), следует использовать концепцию "перегрузки" обработчика событий для окна приложения. После закрытия окна все обработчики автоматически удалятся вместе с окном. А если ты создаешь полноэкранное приложение с кастомным workspace (существующее вне рабочего стола ОС), проще всего использовать назначить обработчик событий для всего рабочего пространства. После выхода из приложения все обработчики также будут удалены. 2) Юишка в майноси построена по принципу Single Thread Application с 1 общим бесконечным циклом на всё рабочее пространство. При возникновении события каждый визуальный элемент на экране получит возможность как-то отреагировать на него через eventHandler. Если тебе нужно параллельно работать в интерфейсе и делать что-то, скажем, раз в 5 сек, то: local workspace = GUI.workspace() local interval = 5 local deadline = uptime + interval -- Добавляем в рабочее пространство кнопки, картинки и т.п. ... -- Назначаем глобальный обработчий событий для всего рабочего пространства workspace.eventHandler = function(_, _, e1) if computer.uptime() > deadline then -- Осуществляем желаемое действие раз в 5 сек deadline = computer.uptime() + interval end end -- Пуллим события с максимально возможной скоростью и нулевой задержкой workspace:start(0) Это я к тому, что не следует создавать вложенных бесконечных циклов, работающих параллельно через имитацию многопоточности, т.к. это масло масляное и против самой концепции STA в рамках однопоточных опенкомпов 3) Если прям уж СИЛЬНО хочется работать с потоковыми библиотеками, то хозяин - барин. Но в этом случае как минимум не следует использовать глобальные переменные типа b, wrk, todraw, которые гарантированно приведут к конфликтам имён и засорят пространство
-
Понял, пардон Для отладки ты всегда можешь заюзать блокирующее окно, чтобы выяснить, какие значения имеют переменные на текущий момент: GUI.alert(b, todraw[b], todraw) Без исходников со всеми ресурсами или как минимум скрина со стектрейсом больше сказать проблематично
-
Без полного сырца с ресурсами черт ногу сломит. Стектрейс ошибки хоть приложи или конкретную строку( С ходу могу лишь сказать, что объекты gui.image создаются некорректно, т.к. 3 аргументом должен идти путь до изображения, а ты прокидываешь булево значение: -- Неверно if images.right then wrk:addChild(gui.image(34, todraw[b].time, images.right)) end -- Верно if images.right then wrk:addChild(gui.image(34, todraw[b].time, "/path/to/image.pic")) end Также удаление элементов из todraw идет без смещения индексов, из-за чего в таблице остаются пустоты. К ошибке вряд ли приведет, но память все же не резиновая: local b = 1 while b < #todraw do if todraw[b]['time'] == -6 then table.remove(todraw, b) b = b - 1 else b = b + 1 end end
-
Оно хранится в поле "name" у прокси сетевого соединения. Каждое соединение - это виртуальный компонент файловой системы, зеркально отражающий физическую фску на удаленной машине и имеющий парочку доп. полей от сетевой либы При подключении к сети компьютер шлёт широковещательный пакет, сообщающий остальным устройствам своё предпочтительное имя. Если пакет принят - создается прокси, в котором и хранится имя. В теории с этими проксями можно работать так же, как с HDD/Floppy, а разница будет лишь в отвратительной скорости обмена данными, хе-хе Вообще подобную инфу можно налутать путем открытия исходника Finder и поиска всего, что связано с "network": https://github.com/IgorTimofeev/MineOS/blob/master/Applications/Finder.app/Main.lua#L228-L242 https://github.com/IgorTimofeev/MineOS/blob/master/Libraries/Network.lua#L398-L400
-
Проверил в последней версии оцелота как софтверную установку биоса, так и через ПКМ. Работает и штатный, и Cyan и майносевский. Мб ты качаешь full версию вместо minified?
-
Спасибо, исправил. Постараюсь внимательнее проверять фичи перед пушем. Или на Тотору спихну, пусть ревьювит))0
-
В этом и заключается вопрос топикстартера: в чем смысл такой защиты, фича ради фичи? Если у дурака имеется доступ к eeprom, то не всё ли равно, вызывать eeprom.makeReadonly() или eeprom.makeReadonly(eeprom.getChecksum())?
-
Да я тебя умоляю, мод там что, каждый раз напрямую из NBT данные гоняет по тысячам фабрик с фасадами и кастами, что возникают такие нагрузки? Возьми gpu.getScreen, modem.isWireless или computer.isRunning - это же чисто логически самые стековые методы, прям стековее некуда, а роняют компьютер так же, как gpu.get на ненулевой буфер, хотя в теории они должны выполняться быстро, как computer.uptime. Падазритильна! И о какой общности интерфейса с любыми значениями речь, если вся работа с Eris сводится к push/pop, а все аргументы луа-функций в любом случае обрабатываются как массивы значений? В чем техническая разница реализации методов компонентов и методов computer/unicode на Scala? Ты просто так говоришь, будто обращение к компонентам какую-то тяжелую артиллерию поднимает - вот мне и интересно, что же за тайное знание там сокрыто А что такое "процессорное время" в рамках работы с компонентами в оцелоте? Суммарное выполнения всех операций относительно длительности тика? Если да, то оно автоматически включает в себя следствие расхода бюджета и сопутствующий оверхед. И если ты численно подтверждаешь, что бюджет практически не расходуется, и если оверхед на практике огромен даже на самых примитивных методах типа isRunning, то значит ли это, что любое обращение к компоненту несет в себе искусственную задержку?
-
Я и не утверждал обратного, это уже какая-то нездоровая полемика. Проясню: 1) Я продемонстрировал, что комп умирает на несколько сек при обращении к gpu.get, предположив, что обращение к ненулевому буферу ни разу не бесплатное 2) Ты сообщил, что доминирует некий оверхед, а расход бюджета при обращении к ненулевому буферу должен быть 2-31 3) Я ответил, что значение в 2-31 слишком мало, и бюджета после 16к вызовов должно оставаться с запасом, и проблема явно в другом месте 4) Ты пояснил, что имел в виду под оверхедом, упомянув нативные либы, интерфейс Lua <> Scala и сам бюджет вызовов 5) Я не согласился, приведя пример с 16к вызовами unicode и computer, имитирующими оверхед без расхода бюджета, и работающий незаметно с точки зрения производительности. Поскольку из примера был исключен лишь расход бюджета, а работа нативных либ и прокидывания данных через Lua <> Scala сохранены, я сделал вывод, что к тормозам приводит именно бюджет Разве это не подтверждает тезис о том, что gpu.get кушает сильно больше 2-31 бюджета? Может быть, каждый вызов прямого метода компонента расходует некое константное кол-во бюджета в дополнение к прописанному в @Callback значению?
-
Я тоже как раз про него и говорил. И по-прежнему не соглашусь. Заменяешь тело функции throttle из примера выше на любой код уровня Lua ↔ Scala типа unicode.sub("abcdef", 1, 2) или computer.uptime(), вызываешь его 160 * 50 * 2 раз перед выводом графики на экран через bitblt - и ничего не изменится. С позиции наблюдателя никаких микро-задержек не будет, bitblt отработает так же, как и без искусственного замедления, потому что, как ты сам подметил, bitblt скушает в сотни (если не тысячи) раз больше бюджета. А теперь вставляем 16к вызовов gpu.get на ненулевой буфер и наслаждаемся мертвым компом. Поэтому смею предположить, что реальный бюджет обращения GPU к ненулевому буферу сильно значимее 2-32, и практический эксперимент это подтверждает Чекнул, ловлю рантаймовую оплеуху. В кубаче работает, так что фиг с ним
-
Разве это не смехотворно малая величина? В таком случае от бюджета серверной стойки в полной комплектации в 1.4 единицы должно оставаться 1.4 - 160 pix * 50 pix * (2 setActiveBuffer + 2 get) * 2-31, то есть 1.3999850988387 Хорошо, предположим, остаток полностью съедают вызовы функций. Пишем для теста любую функцию-заглушку и вызываем её примерно такое же кол-во раз, что и при группировке схожих пикселей: local function throttle() local a = 123 local b = a + 456 local c = a + b ^ a end function screen.update() for i = 1, 160 * 50 * (2 + 2) do throttle() end componentInvoke(GPUAddress, "bitblc", 0) end И... оно работает с той же скоростью, что и в первом примере. То есть на глаз разница не видна, хотя технически она, конечно, есть. Поэтому, имхо, расход бюджета сильно-сильно больше, а хук на вызовы особой роли не играет. Жаль только, что нет фичи вывода значения бюджета через debug.getCallBudgetValue, чтобы знать наверняка Хорошая идея. Закодил, чекнул, скорость действительно чуть возросла, но осталась в пределах ~1 кадра в 3 сек. Вообще мы осознанно убрали bitblc в угоду самописному решению, которое явно проигрывает, так что копать дальше в этом направлении смысла мало. Плюс у нас происходит дублирование вызовов setBackground/setForeground: первый раз во время отрисовки основной графики в буфер, а затем второй раз, но уже в сгруппированном по цветам виде при выводе на экран. Бедная видяшечка, на тайваньских майнинг-фермах и то живется легче (9
-
Идея занятная, но тормозит люто. Подправил либу, после склейки дело дошло до рендеринга лишь спустя ~5 сек, то есть комп фактически виснет на процессе поиска пикселей со схожими цветами на тоннах вызовов setActiveBuffer/get. У меня вообще зародилось смутное подозрение, что все операции над буферами ни разу не zero cost даже с поправкой на искусственный троттлинг хука вызовов в machine.lua. И ладно бы вывод на экран - сам процесс рисования в буфер через setBackground/setForeground/set явно кушает бюджет. Как говорится, численно доказать не могу, но эмпирически чувствую
-
По идее воркспейс оси должен перезапуститься, убив все рабочие приложения и выполнив своеобразный "soft reboot" без физического перезапуска компьютера. Вообще это сочетание клавиш изначально задумывалась в роли прослойки совместимости с опеносевским софтом (на что был благополучно положен болт), а также для экстренного закрытия полноэкранного приложения, взявшего event.pull в монопольное пользование
-
Для теста видеобуферов набросал максимально упрощенный рендерер для майноськи. Без поддержки изображений, прозрачности и транзиций - оставил лишь суровые прямоугольники и цветной текст: Плюсы: расход RAM упал до 25% на полностью инициализированную систему с загруженными (но не отрисованными) иконками. Для слабых машин это очень хороший показатель, и освободившиеся ресурсы можно было бы направить на прикладной многозадачный софт. Минусы: оно лагает сильнее, чем софтверное решение с графоном!11 Но, будем честны, я натягиваю сову на глобус. Концептуально фича крайне сочная, API удобное и не ломает старые проекты, написанные под прямую работу с GPU. Думаю, она будет идеальным решением для узкозадачных юишных софтин типа мониторилок реакторов, кнопочных контроллеров для умного дома, текстовых чатов или рисовалок - иными словами, для всего, что могло слегка подлагивать из-за прямой отрисовки. И если раньше надо было извращаться с порядком операций, экономя каждый тик, то теперь можно кодить гораздо комфортнее. Хотя мне все равно чуточку обидно. Но лишь чуточку.
-
Можно, достаточно присоединить функцию validator к объекту input. Например: local input = GUI.input(2, 2, 30, 3, 0xEEEEEE, 0x555555, 0x999999, 0xFFFFFF, 0x2D2D2D, "Hello world", "Placeholder text")) -- Дозволяем вводить лишь числа input.validator = function(text) return text:match("%d+") end -- Делаем что-то после ввода числа input.onInputFinished = function() end xpcall(abc), а не xpcall(abc()), т.к. вместо безопасного вызова abc через xpcall ты просто вызываешь ее
-
Какие, например? И почему их нельзя реализовать средствами 5.2 через операции в десятичной системе?
-
@num_pi, технически realTime хоста можно узнать через создание временного файла в /tmp/ и fs.lastModified(), хотя тут будет вполне достаточно computer.uptime или os.clock @rootmaster, столкнулся с TLWY, когда требовалось конвертировать жирные 5-мегабайтные картинки из PNG в свой формат. Проблему решил через вызов pullSignal раз в несколько итераций обработки пикселей и несколько секунд работы компьютера. Эти числа подбираются эмпирическим путём, т.к. все зависит от тяжести алгоритма и TPS сервера, хотя, думаю, более умные люди смогут вычислить идеальные значения. Но сам концепт прост как три копейки и работает безотказно: -- Снимаем нагрузку на индексацию таблиц в основном цикле local computerUptime, computerPullSignal = computer.uptime, computer.pullSignal local timeLimit, iterationsLimit, iteration, uptime = 2, 200, 0, computerUptime() local deadline = uptime + timeLimit while true do -- Деляем грязные делишки iteration = iteration + 1 -- Чекаем, нужно ли вообще что-то предпринимать для текущей итерации if iteration > iterationsLimit then iteration, newUptime = 0, computer.uptime() -- Чекаем, нужно ли yieldиться с учётом затраченного времени uptime = computerUptime() if uptime > deadline then computerPullSignal(0) deadline = uptime + timeLimit end end end
-
Ну дк local unicode = require("unicode") local a = "World" local t = {} for i = 1, unicode.len(a) do t[i] = '"' .. unicode.sub(a, i, i) .. '"' end
-
Посимвольно, любой язык: local unicode = require("unicode") local a = "World" local t = {} for i = 1, unicode.len(a) do t[i] = unicode.sub(a, i, i) end Побайтово, english-only local a = "World" local t = {} for i = 1, #a do t[i] = a:sub(i, i) end Через разложение на таблицу байтов, english-only local a = "World" local t = {string.byte(a, 1, #a)} for i = 1, #t do t[i] = string.char(t[i]) end По регулярке, english-only local a = "World" local t = {} local index = 1 for char in a:gmatch(".") do t[index] = char index = index + 1 end По регулярке иным путём, english-only local a = "World" local t = {} local index = 1 a:gsub(".", function(char) t[index] = char index = index + 1 end)
-
Выглядит удобно. А список запрашивается часом не синхронно? Что произойдёт, если, к примеру, я в мгновение обращусь к свойству machine.Components у 50 подключённых машин? Заблокируется ли серверный поток вплоть до получения всех списков? Если да, то было бы неплохо получать компоненты через await machine.GetComponents() без фризов Вообще согласен, особенно если сервер не имеет синхронных методов - в этом случае суффиксы Async бессмысленны. Но тут он имеет!11
- 17 ответов
-
- сеть
- opencomputers
-
(и ещё 2 )
Теги:
-
@num_pi, ты прав, но прости, брат, не удержался!
-
Затестил, очень интересная и довольно удобная реализация, особенно понравилась подписка на ивенты компонентов. Хотя есть вопрос, не дающий покоя: почему некоторые методы машины синхронны (components.TryGet), а другие асинхронны (gpu.Bind), если и тот, и другой выполняются на одной синхронной машине? В случае с Bind я асинхронно ожидаю результат привязки, это логично. А почему тогда список компонентов возвращается синхронно? А в целом было бы очень клёво иметь нейминг по конвенциям майков или как минимум текстовые summary с пояснением, что вот этот метод асинхронен, а этот нет:
- 17 ответов
-
- 1
-
-
- сеть
- opencomputers
-
(и ещё 2 )
Теги:
-
screen.setPrecise(true), по дефолту false
- 2 ответа
-
- 3
-
-
-
Упс хд Ну ничо, wlen решит вопрос
-
Жиза, текстовые вьюверы - это бич любой юишки, что пишется с нуля. По-хорошему после каждого расчёта координатной сетки нужно выполнять авто-перенос оригинального текста с лимитом по ширине, чтобы не напрягать юзера скроллингом. Кстати, в опенкомпах это относительно просто провернуть, т.к. 1 символ занимает ровно 1 пиксель, чего нельзя сказать о десктопных юишках с их measureString(), учётом междустрочных интервалов и прочего шлака А для простого скроллинга достаточно вычислить размер самой длинной строки в исходном тексте и выставить его в качестве лимита прокрутки скроллбара
