Перейти к содержимому

ECS

Гуру
  • Публикации

    533
  • Зарегистрирован

  • Посещение

  • Победитель дней

    203

Все публикации пользователя ECS

  1. Символ "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) В результате выведется
  2. 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
  3. Хранится в роботе, получить объем буфера можно через computer.maxEnergy(), а смотреть "алмазность" можно либо через experience.level(), либо визуально, т.к. с накоплением опыта робот меняет свой цвет сначала на золотой, а затем на алмазный: А выкидывание никто не отменял, его нужно грамотно комбинировать с упаковкой. Например, если робот накопал 9 стаков реда, их можно упаковать в стак блоков, освободив целых 8 слотов под другие ресурсы. Это в любом случае быстрее, чем перемещаться на базу, сбрасывать инвентарь, возвращаться на раскопки и продолжать работу В случае с мусором - да, только выкидывать по черному/белому списку или заправлять апгрейд генератора, если ресурс сжигаемый. Однако мусора много, сканить инвентарь придётся часто, а этот процесс не слишком быстрый. В теории его можно ускорить, реализовав RAM-кеш содержимого инвентаря - но придётся сильно попотеть и учесть тысячу и один нюанс
  4. Не нужна, это задел на дальнейшую разработку с анализом входящих сообщений. Бывают ситуации, когда робот застрял в приватной зоне или бедроке, когда села батарея или сломался инструмент - в этом случае имеет смысл отослать статусное сообщение с координатами робота относительно хоста, а затем отключить питание Вообще роботы с дронами, имхо, самая балдёжная часть мода. Тут и автоматизация рутины, и распределенное выполнение задач, и сетевой код, и инфо-безопасность. Когда кодил аналогичную систему контроля в сурве, то сформулировал для себя несколько рекомендейшнов: Метод modem.setWakeMessage() - имба. Когда робот выполнил все задачи, можно смело его выключать, оставляя где-то на глубине в границах привата. Когда необходимо продолжить работу, шлём сетевой пакет на включение - профит. И энергия сохранена, и нажимать кнопку Power не надо Широковещательные пакеты через modem.broadcast() опасны на публичных серверах, и в 100% случаев станут причиной угона робота. В идеале, когда все машинки скрафчены, необходимо внести адреса их модемов в конфиг на хосте, а впоследствии общаться приватными пакетами через modem.send(). Либо захардкодить в роботах адрес хоста и доверять лишь ему одному, как в примере выше Дополнительные батареи - мусор. Вместо них лучше установить апгрейд опыта, построить ферму кобблы и позволить роботу фармить экспу. Спустя 2-4 реальных часа у тебя раскачается "алмазный" робот с колоссальным буфером энергии Апгрейд навигации для вычисления позиции/поворота - мусор. Вместо него куда дешевле и интереснее накодить софтверную триангуляцию, основанную на перемещениях робота и расстоянии, которое "пролетел" сетевой пакет. А поворот можно определить с помощью геоанализатора, ломания/установки блоков и вращения робота Софтверное позиционирование - имба. Вычисляешь единожды координаты/поворот робота - и корректируешь их при вызове move/turn. Взамен появляется возможность автоматизировать перемещение в любую указанную точку. При отключении питания имеет смысл сохранять эти данные на диске, либо определять их автоматически при включении Геоанализатор - легальный чит. Однако использовать его в штатном режиме, сканируя вертикальными "столбцами" - выстрел в ногу, т.к. точность результатов на расстоянии в 10+ блоков будет отвратная. Вместо этого стоит заюзать опциональные аргументы scan(), анализируя небольшие горизонтальные плоскости 8х8 блоков вокруг робота, постепенно прокапывая вниз. Точность при этом станет как советском станке Экран/клавиатура/дисковод и полноценная ОС - штуки ситуативные, т.к. стоимость сборки улетает в космос, а выхлоп сомнительный. Мнение не навязываю, но я предпочитаю ставить больше апгрейдов инвентаря/крафтинг/редстоун-плату/etc., делая машинку универсальнее и контролируя её по сети Апгрейд крафтинга очень недооценён. Каким бы большим ни был инвентарь, он гарантированно заполнится всякими андезитами/мусоритами. Эту проблему в соло решает крафтинг, упаковывающий ресурсы в стаки, особенно на серверах с модами типа экстраутилит, позволяющими "сжимать" кобблу Жёсткий диск 1 тира - топ за свои деньги. Всегда приятно иметь возможность сохранять/загружать координаты робота или довольно объёмные "снимки" местности с геоанализатора
  5. Эта штука ждёт каких-либо сигналов в течение 3 секунд. Если сигнал получен - pullSignal вернёт информацию о нём досрочно. Если сигналов не было - pullSignal будет честно ждать 3 секунды, а затем вернет nil Вообще, как я понял, тебе нужен некий аналог os.sleep(3) из OpenOS, который реализован как раз на чистом pullSignal. Можно скопировать его из исходников На самом деле не относится, это на вики мешанина. Суперглобалки component/computer/robot/unicode/bit32, а также штатные библиотеки Lua доступны отовсюду. Все остальное - софтверные фичи OpenOS
  6. Библиотека 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. Непривычно и неочевидно - да, есть такое
  7. Проверяй наличие файлов и корректность вводимых путей. Интереса ради загрузил майн, проверил - всё сработало, как и задумано: Управляющий скрипт /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:
  8. Ага, опечатка, поправил, спсибо
  9. @WheatComp Если по-читерски, то можно сдюпнуть жёсткий диск одного робота, вставить его в остальные и работать в одной общей папке Если по-честному, то имеет смысл дать возможность каждому роботу выполнять произвольный код, присылаемый компьютером-хостом по беспроводной сети. Это позволит избавиться от OpenOS, жёсткого диска и упростить сборку робота за счёт более дешёвых компонентов: 1) Крафтим 20 чистых EEPROM и беспроводных модемов 2) Прошиваем их скриптом-ресивером: 3) Вставляем прошитые EEPROM с модемами в роботов 4) Пишем управляющий скрипт для компьютера-хоста. Предполагаю, что на нём будет использоваться OpenOS: 5) Запускаем всех роботов и отсылаешь им любой файл с жёсткого диска на исполнение командой send robots/example.lua Единственный нюанс - работоспособность кода выше чекнуть не могу, т.к. майна под рукой нет, но общий концепт, думаю, понятен
  10. Это не возымеет эффекта, т.к. библиотека package реализована средствами OpenOS, а не мода. То есть ей доступны те же данные, что и игровому жёсткому диску. А ему в свою очередь доступны только данные в рамках директории игрового сейва - это захардкожено из соображений серверной безопасности, и обойти не получится Вероятно, package задумывалась как полный аналог одноименной библиотеки в "реальной" версии Lua - отсюда и путаница
  11. Можно, button.disabled = false. Но оно меняет визуальный стиль ¯\_(ツ)_/¯ По идее каждая кнопка имеет таблицу .colors, где можно кастомизировать все цвета. Так что можно заюзать что-то наподобие button.colors.disabled = button.colors.default Но с окнами это не прокатит, т.к. "общего" решения для отключения обработки событий не предусмотрено. Кстати, его не особенно сложно имплементировать, буду рад PR, если захочется покопаться
  12. Увы, нет, это не было предусмотрено "из коробки". Как я понял, речь идёт о неком аналоге IsHitTestVisible, когда система должна игнорировать touch-ивенты, но без смены визуального стиля элементов. Причём глобально, а не только для кнопок. На текущий момент это можно реализовать лишь с помощью перегрузки: window.isEventHandlingEnabled = true local originalWindowEventHandler = window.eventHandler window.eventHandler = function(workspace, window, ...) if window.isEventHandlingEnabled then originalWindowEventHandler(workspace, window, ...) end end
  13. ECS

    Not enough memory fs.writeTable

    Для print заданы ограничения сериализатора, которые отсутствуют в writeTable А какие именно - не скажу, сам думай. Не люблю приказной формат дискуссий)0
  14. Хост маркета располагается на домашней OrangePI и пару недель не отвечает на пинги. Может быть, умерла загрузочная SD-карта, которая родилась с нокией le papan 15 лет назад и давно на ладан дышит. Или, что более вероятно, сработало реле в распред. щитке, и питание полностью отключилось (прощай, заморозка в холодосе). Или вообще роутер с алика самопроизвольно перепрошился и устал работать. Сложно сказать. Бекапы валяются на внешнем диске на пыльных антресолях, а сам я за тридевять земель от дома, вернусь ориентировочно к концу лета - примерно тогда и гляну, что там случилось
  15. ECS

    screen не пашет

    Workspace создается за пределами экрана, первые два параметра - это x и y. Подробнее в доке Переменная "a" переопределена, из-за чего теряется объект, созданный в vector.new(). Т.е. каждая новая фигура добавляется не в родительский object, а в предыдущую фигуру Фиксим, радуемся: Это что касалось логики. Теперь по коду: осмелюсь прогнать его через Lua Beautifier, оформить ООП и дать человеческие названия переменным, т.к. "a", "what" или "toendobject" имеют сомнительную информативность. Использовать его или нет - дело, офк, твоё Приложение: Либа:
  16. ECS

    screen не пашет

    Исходники не полные, инфы о создании элементов фигур в 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 не округлены, что выливается в ошибки экранной либы. Но опять же, без полных сырцов что-либо дельное сказать сложно
  17. -- Копируем переменную 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
  18. Вновь ничего не понятно, но
  19. А питания хватает? Была похожая ситуация, когда некоторые мониторы отключались из-за подключения лишь одного энерговхода
  20. ECS

    AutoResolution в MineOs

    Капец, я еле понял, о чём речь. Bзмени второй аргумент gpu.bind на false, т.к. по умолчанию разрешение автоматически сбрасывается на maxResolution. Из документации: bind(address: string[, reset: boolean=true])
  21. ECS

    MineOs GUI Container

    Дык его попросту нельзя использовать. Либа сама делает всю работу, обрабатывая ивенты по-своему и творя внутреннюю магию. Если используешь - получаешь "unexpected behaviour" со всеми вытекающими. Поэтому либо повторяй в точности всю "магию", либо присоединяй eventHandler как положено и не парься Для твоей задачи это не требуется, т.к. удержание клавиш нажатыми в любом случае генерирует бесконечный поток событий key_down, позволяя персонажу двигаться ходить непрерывно. Авто-пуллинг событий впустую нагружает компьютер, обрабатывая их через либу. Иногда это действительно необходимо (пример с опросом реакторов), но чаще всего нет localX/localY отвечают за положение элемента внутри родительского контейнера, а x/y - за позицию на экране во время отрисовки. При этом x/y рассчитываются автоматически и используются только во время операций отрисовки. Вообще все подробности имеются в доке, которую было бы неплохо чекнуть localX/localY Дык имеют же. Читай доку!!11
  22. ECS

    MineOs GUI Container

    Вполне вероятно, что смещение белого прямоугольника - это баг отрисовки. А, может быть, и нет, т.к. либа юзается не по доке: 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
  23. ECS

    3D Test казус

    Ничего не понял, кроме того, что они летают :p Код писался в докембрийскую эпоху, и сейчас уже не вспомнить, как там что было устроено. И тем более не пофиксить, так что увы
  24. А чего я-то, это все он! Видимо, хочет поставить старую оську, исходники которой уже давно утеряны, а пастбин акк заблочен из-за санкций
×
×
  • Создать...