ECS
Гуру-
Публикации
533 -
Зарегистрирован
-
Посещение
-
Победитель дней
203
Тип публикации
Блоги
Профили
Форум
Багтрекер
Магазин
Все публикации пользователя ECS
-
tankTable[1].amount
-
Символ "s" поставил лишний, сорян. Я тебе сам принцип хотел показать, что нужно сначала пройтись по всем имеющимся танкам, а затем уже обращаться к их полям. Если нужен самодельный сериализатор для любого типа таблиц, то можно написать что-то вроде tank1 = {amount = 222, capacity = 333, nestedTable = {1, 2, 3}} tank2 = {amount = 452, capacity = 349, nestedTable = {4, 5, 6}} tankTable = {tank1, tank2} local function printTableContents(source, name, indentator) indentator = indentator or "" name = name or "" print(indentator .. name .. "{") for key, value in pairs(source) do if type(value) == "table" then printTableContents(value, tostring(key) .. " = ", (indentator or "") .. " ") else print(indentator .. " " .. tostring(key) .. " = " .. tostring(value)) end end print(indentator .. "}") end printTableContents(tankTable) В результате выведется
-
tank1 = {amount = 222, capacity = 333} tank2 = {amount = 452, capacity = 349} tankTable = {tank1, tank2} -- Сначала перебираем танки for tankIndex, tank in ipairs(tanksTable) do -- Затем все поля танка for key, value in pairs(tank) do print(key, value) end end
-
Хранится в роботе, получить объем буфера можно через computer.maxEnergy(), а смотреть "алмазность" можно либо через experience.level(), либо визуально, т.к. с накоплением опыта робот меняет свой цвет сначала на золотой, а затем на алмазный: А выкидывание никто не отменял, его нужно грамотно комбинировать с упаковкой. Например, если робот накопал 9 стаков реда, их можно упаковать в стак блоков, освободив целых 8 слотов под другие ресурсы. Это в любом случае быстрее, чем перемещаться на базу, сбрасывать инвентарь, возвращаться на раскопки и продолжать работу В случае с мусором - да, только выкидывать по черному/белому списку или заправлять апгрейд генератора, если ресурс сжигаемый. Однако мусора много, сканить инвентарь придётся часто, а этот процесс не слишком быстрый. В теории его можно ускорить, реализовав RAM-кеш содержимого инвентаря - но придётся сильно попотеть и учесть тысячу и один нюанс
-
Не нужна, это задел на дальнейшую разработку с анализом входящих сообщений. Бывают ситуации, когда робот застрял в приватной зоне или бедроке, когда села батарея или сломался инструмент - в этом случае имеет смысл отослать статусное сообщение с координатами робота относительно хоста, а затем отключить питание Вообще роботы с дронами, имхо, самая балдёжная часть мода. Тут и автоматизация рутины, и распределенное выполнение задач, и сетевой код, и инфо-безопасность. Когда кодил аналогичную систему контроля в сурве, то сформулировал для себя несколько рекомендейшнов: Метод modem.setWakeMessage() - имба. Когда робот выполнил все задачи, можно смело его выключать, оставляя где-то на глубине в границах привата. Когда необходимо продолжить работу, шлём сетевой пакет на включение - профит. И энергия сохранена, и нажимать кнопку Power не надо Широковещательные пакеты через modem.broadcast() опасны на публичных серверах, и в 100% случаев станут причиной угона робота. В идеале, когда все машинки скрафчены, необходимо внести адреса их модемов в конфиг на хосте, а впоследствии общаться приватными пакетами через modem.send(). Либо захардкодить в роботах адрес хоста и доверять лишь ему одному, как в примере выше Дополнительные батареи - мусор. Вместо них лучше установить апгрейд опыта, построить ферму кобблы и позволить роботу фармить экспу. Спустя 2-4 реальных часа у тебя раскачается "алмазный" робот с колоссальным буфером энергии Апгрейд навигации для вычисления позиции/поворота - мусор. Вместо него куда дешевле и интереснее накодить софтверную триангуляцию, основанную на перемещениях робота и расстоянии, которое "пролетел" сетевой пакет. А поворот можно определить с помощью геоанализатора, ломания/установки блоков и вращения робота Софтверное позиционирование - имба. Вычисляешь единожды координаты/поворот робота - и корректируешь их при вызове move/turn. Взамен появляется возможность автоматизировать перемещение в любую указанную точку. При отключении питания имеет смысл сохранять эти данные на диске, либо определять их автоматически при включении Геоанализатор - легальный чит. Однако использовать его в штатном режиме, сканируя вертикальными "столбцами" - выстрел в ногу, т.к. точность результатов на расстоянии в 10+ блоков будет отвратная. Вместо этого стоит заюзать опциональные аргументы scan(), анализируя небольшие горизонтальные плоскости 8х8 блоков вокруг робота, постепенно прокапывая вниз. Точность при этом станет как советском станке Экран/клавиатура/дисковод и полноценная ОС - штуки ситуативные, т.к. стоимость сборки улетает в космос, а выхлоп сомнительный. Мнение не навязываю, но я предпочитаю ставить больше апгрейдов инвентаря/крафтинг/редстоун-плату/etc., делая машинку универсальнее и контролируя её по сети Апгрейд крафтинга очень недооценён. Каким бы большим ни был инвентарь, он гарантированно заполнится всякими андезитами/мусоритами. Эту проблему в соло решает крафтинг, упаковывающий ресурсы в стаки, особенно на серверах с модами типа экстраутилит, позволяющими "сжимать" кобблу Жёсткий диск 1 тира - топ за свои деньги. Всегда приятно иметь возможность сохранять/загружать координаты робота или довольно объёмные "снимки" местности с геоанализатора
-
Эта штука ждёт каких-либо сигналов в течение 3 секунд. Если сигнал получен - pullSignal вернёт информацию о нём досрочно. Если сигналов не было - pullSignal будет честно ждать 3 секунды, а затем вернет nil Вообще, как я понял, тебе нужен некий аналог os.sleep(3) из OpenOS, который реализован как раз на чистом pullSignal. Можно скопировать его из исходников На самом деле не относится, это на вики мешанина. Суперглобалки component/computer/robot/unicode/bit32, а также штатные библиотеки Lua доступны отовсюду. Все остальное - софтверные фичи OpenOS
-
Библиотека filesystem абстрагируется от действий текущего юзера и рабочей директории, предоставляя более "сырой" доступ к файловой системе без высокоуровневых проверок. Для поддержки поиска по раб. директории следует обратиться к методу shell.resolve(path), который используется большинством штатных скриптов в /bin/. Посмотри на отправляющий код с пред. сообщения - там я как раз добавил эту фичу для удобства Всё верно. В десктопном Lua ты получил бы что-то наподобие: А в OpenComputers уже нет, т.к. глобальной переменной arg вовсе не существует: Все входные аргументы мы получаем вручную через args = {...}, создавая при этом самую обычную переменную. Она не какая-то магическая, не системная. Её и назвать можно как угодно, хоть someWeirdDots = {...}, тут уж воля фантазии Согласен, хотя это скорее дело привычки. Всегда можно скопировать таблицу направлений из исходников Sides API, и воспользоваться ей для движения робота в нужную сторону, если вводить непонятные цифры а-ля robot.move(1/2/3/4) дискомфортно Как раз по этой ссылке и перечислены все остальные "низкоуровневые" команды, других попросту не существует в компоненте robot. Пикча для наглядности: Например, back/up/down реализуются софтверно средствами OpenOS. При этом robot.back() из OpenOS эквивалентен компонентному вызову robot.move(2). Вообще крайне рекомендую чекнуть исходники по пред. ссылке - там много всего интересного, и на деле окажется, что работа с "чистым" роботом ничуть не сложнее, чем с библиотекой из OpenOS. Непривычно и неочевидно - да, есть такое
-
Проверяй наличие файлов и корректность вводимых путей. Интереса ради загрузил майн, проверил - всё сработало, как и задумано: Управляющий скрипт /home/send.lua: Микропрограмма-ресивер для робота /home/eeprom.lua: Исполняемый код, отсылаемый роботам по сети /home/robot.lua: Команда для отсылки: send robot.lua Результат: Движение робота реализуется самим роботом, а не OpenOS. Как правило, любая ОС в OpenComputers - это софтверная оболочка, функционирующая поверх аппаратной части, и предоставляющая набор библиотек, упрощающих разработку софта. Например, в случае с роботами OpenOS оборачивает компонент robot в библиотеку robot, предоставляющую набор шорткатов. То же самое и с глобальной функцией require - её попросту нет в "голых" роботах, управляемых из-под EEPROM Использовать ОС крайне удобно, когда речь идет об одном роботе, хранящем пользовательские скрипты и управляемом напрямую через экран/клавиатуру. Однако в случае с роем такое решение контр-продуктивно, т. к. любая ОС потребляет ресурсы и требует крафта более дорогостоящих компонентов - в частности, планок памяти и жёстких дисков. Это всё равно что ставить Debian на сеть устройств для капельного полива домашних растений - ну то есть да, это возможно, а зачем? Разумнее прибегнуть к концепции микропрограмм на EEPROM, которые относительно дёшевы в плане крафта, а профит в виде освободившихся слотов под компоненты существенный. Заодно можно получить интересный опыт по "низкоуровневой" разработке под опенкомпы: -- Робот с OpenOS local robot = require("robot") robot.moveUp() robot.turnRight() robot.swing() -- Робот с EEPROM local robot = component.proxy(component.list("robot")()) robot.move(1) robot.turn(true) robot.swing(3) Таблицы component/computer/robot/unicode/bit32 являются суперглобальными и доступны сразу при запуске микропрограммы EEPROM, однако во время инициализации OpenOS они маскируются из соображений консистентности кода. Поэтому при работе из-под EEPROM вызов require не требуется, а из-под OpenOS уже требуется Верстаки, контроллеры инвентаря и ёмкости - это аппаратные компоненты, функционирующие самостоятельно и не требующие OpenOS. Любая ОС - это просто средство доступа к компонентам, причём одно из многих: -- Робот с OpenOS local component = require("component") local sides = require("sides") local crafting = component.crafting local inventoryController = component.inventory_controller local tankController = component.tank_controller crafting.craft(10) inventoryController.dropIntoSlot(sides.front, 10) tankController.drain() -- Робот с EEPROM local crafting = component.proxy(component.list("crafting")()) local inventoryController = component.proxy(component.list("inventory_controller")()) local tankController = component.proxy(component.list("tank_controller")()) crafting.craft(10) inventoryController.dropIntoSlot(3, 10) tankController.drain() Как видно, разница в коде несущественна, отличие лишь в способе получения доступа к ним и в наличии упрощающих библиотек типа sides Чтобы прояснить ситуацию: никто не призывает тебя использовать голый EEPROM вместо классического подхода с HDD/OpenOS. Разрабатывай так, как считаешь комфортным и оптимальным для себя - я лишь указал один из способов решения поставленной задачи, который использовал при выживании, и который сам считаю оптимальным Если тебе требуется весь богатый функционал, поставляемый OpenOS для роботов, ничто не мешает модифицировать скрипт-ресивер таким образом, чтобы он работал из-под OpenOS:
-
Ага, опечатка, поправил, спсибо
-
@WheatComp Если по-читерски, то можно сдюпнуть жёсткий диск одного робота, вставить его в остальные и работать в одной общей папке Если по-честному, то имеет смысл дать возможность каждому роботу выполнять произвольный код, присылаемый компьютером-хостом по беспроводной сети. Это позволит избавиться от OpenOS, жёсткого диска и упростить сборку робота за счёт более дешёвых компонентов: 1) Крафтим 20 чистых EEPROM и беспроводных модемов 2) Прошиваем их скриптом-ресивером: 3) Вставляем прошитые EEPROM с модемами в роботов 4) Пишем управляющий скрипт для компьютера-хоста. Предполагаю, что на нём будет использоваться OpenOS: 5) Запускаем всех роботов и отсылаешь им любой файл с жёсткого диска на исполнение командой send robots/example.lua Единственный нюанс - работоспособность кода выше чекнуть не могу, т.к. майна под рукой нет, но общий концепт, думаю, понятен
-
Это не возымеет эффекта, т.к. библиотека package реализована средствами OpenOS, а не мода. То есть ей доступны те же данные, что и игровому жёсткому диску. А ему в свою очередь доступны только данные в рамках директории игрового сейва - это захардкожено из соображений серверной безопасности, и обойти не получится Вероятно, package задумывалась как полный аналог одноименной библиотеки в "реальной" версии Lua - отсюда и путаница
-
Можно, button.disabled = false. Но оно меняет визуальный стиль ¯\_(ツ)_/¯ По идее каждая кнопка имеет таблицу .colors, где можно кастомизировать все цвета. Так что можно заюзать что-то наподобие button.colors.disabled = button.colors.default Но с окнами это не прокатит, т.к. "общего" решения для отключения обработки событий не предусмотрено. Кстати, его не особенно сложно имплементировать, буду рад PR, если захочется покопаться
-
Увы, нет, это не было предусмотрено "из коробки". Как я понял, речь идёт о неком аналоге IsHitTestVisible, когда система должна игнорировать touch-ивенты, но без смены визуального стиля элементов. Причём глобально, а не только для кнопок. На текущий момент это можно реализовать лишь с помощью перегрузки: window.isEventHandlingEnabled = true local originalWindowEventHandler = window.eventHandler window.eventHandler = function(workspace, window, ...) if window.isEventHandlingEnabled then originalWindowEventHandler(workspace, window, ...) end end
-
Для print заданы ограничения сериализатора, которые отсутствуют в writeTable А какие именно - не скажу, сам думай. Не люблю приказной формат дискуссий)0
- 1 ответ
-
- 3
-
-
-
Хост маркета располагается на домашней OrangePI и пару недель не отвечает на пинги. Может быть, умерла загрузочная SD-карта, которая родилась с нокией le papan 15 лет назад и давно на ладан дышит. Или, что более вероятно, сработало реле в распред. щитке, и питание полностью отключилось (прощай, заморозка в холодосе). Или вообще роутер с алика самопроизвольно перепрошился и устал работать. Сложно сказать. Бекапы валяются на внешнем диске на пыльных антресолях, а сам я за тридевять земель от дома, вернусь ориентировочно к концу лета - примерно тогда и гляну, что там случилось
-
Workspace создается за пределами экрана, первые два параметра - это x и y. Подробнее в доке Переменная "a" переопределена, из-за чего теряется объект, созданный в vector.new(). Т.е. каждая новая фигура добавляется не в родительский object, а в предыдущую фигуру Фиксим, радуемся: Это что касалось логики. Теперь по коду: осмелюсь прогнать его через Lua Beautifier, оформить ООП и дать человеческие названия переменным, т.к. "a", "what" или "toendobject" имеют сомнительную информативность. Использовать его или нет - дело, офк, твоё Приложение: Либа:
- 3 ответа
-
- 2
-
-
Исходники не полные, инфы о создании элементов фигур в what нет, поэтому чёрт его знает. На текущий момент в глаза бросается лишь использование глобальных экранных координат вместо локальных координат объекта в методе отрисовки. Все методы либы screen работают с экраном, а не с объектом toendobject, у которого есть свои собственные координаты. Поэтому для корректной отрисовки фигур нужно будет юзать конструкцию вида screen.drawRectangle( toendobject.x + what[i].x, toendobject.y + what[i].y, toendobject.x + what[i].x1, toendobject.y + what[i].y1, what[i].color, 0xFFFFFF, 'R' ) Ещё мб ты не вызываешь метод workspace:draw() после добавления всех элементов в него, поэтому никаких новых данных на экране и не появляется И напоследок, вполне может быть, что x/y/x1/y1 не округлены, что выливается в ошибки экранной либы. Но опять же, без полных сырцов что-либо дельное сказать сложно
-
-- Копируем переменную what в toendobject toendobject.what = what -- Определяем метод отрисовки toendobject toendobject.draw = function(toendobject) -- Обращаемся к скопированной ранее переменной for i = 1, #toendobject.what do if toendobject.what[i] == "line" then ... end end end
- 2 ответа
-
- 1
-
-
Вновь ничего не понятно, но
-
А питания хватает? Была похожая ситуация, когда некоторые мониторы отключались из-за подключения лишь одного энерговхода
-
Капец, я еле понял, о чём речь. Bзмени второй аргумент gpu.bind на false, т.к. по умолчанию разрешение автоматически сбрасывается на maxResolution. Из документации: bind(address: string[, reset: boolean=true])
-
Дык его попросту нельзя использовать. Либа сама делает всю работу, обрабатывая ивенты по-своему и творя внутреннюю магию. Если используешь - получаешь "unexpected behaviour" со всеми вытекающими. Поэтому либо повторяй в точности всю "магию", либо присоединяй eventHandler как положено и не парься Для твоей задачи это не требуется, т.к. удержание клавиш нажатыми в любом случае генерирует бесконечный поток событий key_down, позволяя персонажу двигаться ходить непрерывно. Авто-пуллинг событий впустую нагружает компьютер, обрабатывая их через либу. Иногда это действительно необходимо (пример с опросом реакторов), но чаще всего нет localX/localY отвечают за положение элемента внутри родительского контейнера, а x/y - за позицию на экране во время отрисовки. При этом x/y рассчитываются автоматически и используются только во время операций отрисовки. Вообще все подробности имеются в доке, которую было бы неплохо чекнуть localX/localY Дык имеют же. Читай доку!!11
-
Вполне вероятно, что смещение белого прямоугольника - это баг отрисовки. А, может быть, и нет, т.к. либа юзается не по доке: 1) Обработка событий встроена, workspace.start() сам по себе запускает бесконечный цикл пуллинга событий, и делать это вручную через while true нет смысла: wk.eventHandler = function(e1, e2, e3, e4, e5, e6) ... end wk:start(0.01) 2) Непонятно, зачем конкретно в твоём случае используется таймаут поллинга в 0.01 сек. Эта фича используется в довольно редких ситуациях, когда нужно делать что-то с заданным интервалом. Например, опрашивать внешние компоненты типа реакторов или перемещать визуальные элементы в играх раз в N сек. Если тебе требуется лишь анализ нажатия клавиш, то: bg.eventHandler = function(e1, e2, e3, e4, e5, e6) if e1 == "key_down" then -- A if e3 == 30 then ... wk:draw() -- D else if e3 == 32 then ... wk:draw() end end end wk:start(0.01) 3) Изменять экранные координаты объекта бесполезно, т.к. они рассчитываются автоматически и используются только во время вызова метода draw(). Чтобы изменить позицию элемента в родительском контейнере, используй localX/localY: -- Нельзя player.x = player.x - 2 -- Можно player.localX = player.localX - 2 4) Нет смысла удалять и пересоздавать объекты картинок при каждом ивенте. Если тебе нужно попросту заменить картинку в существующем виджете, то: local playerpic = wk:addChild(gui.image(50,25,images['Man Right'])) bg.eventHandler = function(e1, e2, e3, e4, e5, e6) if e1 == "key_down" then -- A if e3 == 30 then player.facing = 'Left' playerpic.image = images['Man ' .. player.facing] wk:draw() end end end 5) Можно вообще создать собственный виджет "player", определив ему метод отрисовки и не собирать его из GUI.image. Он и работать будет быстрее, и все поля будут храниться в одном месте, и любой кастом можно будет оформить за пару строк кода: local player = wk:addChild(gui.object(50, 25, 8, 4)) player.facing = 'Left' player.draw = function(player) screen.drawImage(player.x, player.y, images['Man ' .. player.facing] end
- 3 ответа
-
- 4
-
-
Ничего не понял, кроме того, что они летают :p Код писался в докембрийскую эпоху, и сейчас уже не вспомнить, как там что было устроено. И тем более не пофиксить, так что увы
- 1 ответ
-
- 1
-
-
А чего я-то, это все он! Видимо, хочет поставить старую оську, исходники которой уже давно утеряны, а пастбин акк заблочен из-за санкций
