eu_tomat
-
Публикации
2 666 -
Зарегистрирован
-
Посещение
-
Победитель дней
331
Сообщения, опубликованные пользователем eu_tomat
-
-
Для информации, чтобы читателям было понятно, что здесь происходит: @serafim выложил свои варианты программ, но пока решил притормозить, чтобы не участвовать в создании лагодромов. Его позиция понятна, темы автора заказа вызывают противоречивые чувства.
-
1 час назад, serafim сказал:идея интересная
Начнём с установщика блоков:
Скрытый текстlocal sides = require "sides" local robot = require "robot" local component = require "component" local active_slot = 1 size=robot.inventorySize() local function Text() os.execute("cls") print("РОБОТ РАБОТАЕТ!! Создатель - GooodGame") print("Доработал-atomzerg") end Text() while true do robot.select(active_slot) if robot.count(active_slot) == 0 then active_slot = active_slot + 1 end if robot.select(active_slot) ==size then active_slot = 1 end if robot.place() == false then active_slot = active_slot + 1 end if active_slot == size then active_slot = 1 end robot.place() end
Предварительный, грубый анализ:
- Программа в основном расходует время на выполнение бесконечного цикла.
- Внутри бесконечного цикла безусловно выполняются следующие операции:
- Два раза выполняется robot.select, затрачивая 0.05 сек на вызов.
- Один раз robot.place, затрачивая 0.4 сек на вызов
- Один раз robot.count, на вызов тратится примерно 5E-5 сек времени.
Успешные вызовы robot.place приближают игрока к цели, нет смысла уменьшать количество этих вызовов, но есть смысл подготовить робота таким образом, чтобы каждый вызов был успешным, т.к. выполнение неудачного вызова требует 0.05 сек времени.
Программа проверяет успешность операции кодом: if robot.place() == false, но из этого делается неверный вывод, будто бы закончились предметы в слоте. Это не верно. Такое условие сообщает о том, что не удалось установить блок в мир: скорее всего, есть какая-то помеха. Для проверки наличия предмета в слоте могло бы подойти условие if robot.place() == nil, но эту проверку можно гораздо быстрее осуществить с помощью robot.count(). В случае же, если не удалось установить блок, имеющийся в слоте робота, требуется просто подождать, пока освободится пространство в координатах установки.
Также неудача при установке блока возможна в случае, когда в инвентарь робота попал предмет, не являющийся блоком. Но это уже проблема корректности настройки фильтров в логистических сетях на базе игрока. Думаю, этот вариант вообще не имеет смысла анализировать в программе.
Вызовы robot.select() приближают игрока к цели только в том случае, если текущий слот инвентаря опустел. И при достаточно быстром заполнении инвентаря робота блоками руды требуется не более 1/64 этой операции на одну итерации цикла. Минимизируя количество вызовов этой операции удастся сэкономить 0.05*2 - 0.05/64 секунд на одну итерации цикла. Относительно времени, затраченного на основную операцию, экономия составит 19.84%.
-
@Alex_Bolkov Что именно там должно быть зациклено? Надо сделать всё то же самое, только в бесконечном цикле?
Тогда вместо этой строки:
Repeat()
Пишем:
while true do Repeat() end
-
1
-
1
-
-
@serafim Ну, ясно. Нет особого смысла направлять роботов в один блок, если речь не идёт об экономии на дорогом инструменте.
Теперь вернёмся к теме заказа. Меня эта задачка заинтересовала своей экстремальностью, поэтому я потратил много времени на исследование способов, позволяющих достичь максимальной скорости переработки руды. Мы с автором заказа обсуждали в дискорде возможные варианты, но он отверг все предложенные мной улучшения схемы. Он сопротивляется каким-либо изменениям изначальной схемы и разрешает только оптимизировать код программ.
При таких условиях для меня это совершенно неинтересная задача с точки зрения кодинга. Но благодаря примитивности эти двух программ я считаю их хорошими примерами для оптимизации. Если я и перепишу эти две программы, то это будет в формате блога с раскрытием темы оптимизации.
Если же тебе интересна задача, ты можешь сделать это раньше меня и без лишних слов, аккуратно с нуля написав обе программы, не используя лишних операций или заменив медленные операции более быстрыми.
Также мы можем совместно работать над новым вариантом, если тебе интересен такой формат: ты пишешь код, а я анализирую его эффективность. В этом случае мы с тобой сможем раскрыть тему оптимизации последовательно, пост за постом.
Какой из вариантов работы над этим заказом тебе наиболее интересен?
-
@serafim Что-то я запутался.
36 минут назад, serafim сказал:Идея в том чтоб не заморачиваться с ПО, роботы сами будут ставить или рубить руду в зависимости от того кто раньше успеет
Это понятно. Но если вдобавок к этому мы разместим роботов так, чтобы каждый из них рубил в своём блоке, то о синхронизации вообще не надо будет думать. Каков смысл общего блока для совместной работы двух роботов, если у каждого есть свой инструмент для рубки?
40 минут назад, serafim сказал:Такой способ тоже хорош и экономный в плане инструмента и зарядчика
Какой способ хорош? Мой с тремя установщиками и одним рубщиком? Или тот, который предложил ты с двумя роботами?
-
32 минуты назад, serafim сказал:Синхронизировать двух роботов на одну задачу оказалось не так просто как думалось, перепробовал пол сотни вариантов пока получилось хоть что-то не сильно лагучее
Два робота совместно ставят и рубят один и тот же блок получая ускорение
А в чём заключается преимущество именно такой схемы параллельной работы? Какой смысл размещать независимых роботов так, чтобы они имели общий блок для переработки руды, если проще сделать эти блоки отдельными для каждого робота? Это позволило бы вообще не задумываться о синхронизации роботов
Мне было понятно, когда один робот рубил руду, а второй робот её устанавливал. Это позволяло повысить эффективность использования дорогого инструмента. Развивая эту идею, я использовал третьего и даже четвертого робота: три робота устанавливали руду в один общий блок, а четвёртый рубил руду в этом блоке.
Но что даёт этот трюк с общим блоком в схеме на двух независимых роботах, когда каждый из них рубит своим инструментом?
-
1 час назад, Bs0Dd сказал:Учел, добавил проверку на выгружаемость (проверяется также, выгружен ли слот полностью), иначе отдых
Бонусом добавлено:
...
Возможно, опять же, можно где-то сделать и лучше
Улучшать программу можно бесконечно. Функционал растёт, увеличивается количество мест, где может возникнуть ошибка. Возникает куча вариантов их исправления.
Например, что произойдёт, если в заряднике для инструмента рабочий слот окажется занятым? Игрок может что-то закинуть в него на зарядку. Значит, надо писать инструкцию, что зарядник должен быть свободен. Или робот должен временно вынимать этот инструмент, и вместо него класть на зарядку инструмент робота. Или просто выдавать ошибку и ждать. Но такую ситуацию в том или ином виде желательно предусмотреть.
Код задержки начал так часто использоваться и копироваться, что пора выносить его в отдельную функцию. В текущем виде код разбухает, и есть шанс не заметить мелкую ошибку, допущенную при копировании.
То же самое и со звуковыми сигналами: желательно разработать какую-то кодовую систему сигналов и вынести генерацию звука в отдельную функцию. Это упростит дальнейшую доработку программы, если она потребуется.
И вообще, при большом разнообразии звуковых сигналов имеет смысл всё-таки ограничить их количество и добавить в робота видеокарту и монитор, чтобы выводить сообщения в более понятном виде. А звуковой сигнал можно использовать для привлечения внимания игрока. Впрочем, это моё субъективное отношение к проблеме оповещения, я не настаиваю именно на таком решении.
Ещё я вижу проблему в этом участке кода:
while r.durability() < lowcharge do
Сейчас в случае, если автоматическая подзарядка не предусмотрена, робот просто ожидает, когда инструмент в его слоте зарядится. Сам собой от одного лишь ожидания он не зарядится, поэтому игрок в какой-то момент вручную извлечёт инструмент из робота для зарядки. А в это время на очередной итерации цикла программа прервётся ошибкой при попытке сравнения разных типов.
Также желательно сбрасывать autocharge в false при отсутствии контроллера инвентаря или же обрабатывать ошибку в процессе работы, если, например, контроллер инвентаря съёмный. Или дожидаться его установки игроком. Тут, опять же, есть большой простор для обработки этой ситуации.
-
21 минуту назад, Bs0Dd сказал:Исправил и это упущение (надеюсь правильно).
Вроде бы правильно (если я ничего не упустил). Теперь программа стала даже чуть лучше оригинала. Но можно сделать ещё чуть лучше. Например, было бы полезным проверять успешность выгрузки предметов из слота и также впадать в спячку на время, пока игрок не освободит инвентарь. Пауза при неудачной выгрузке предметов не мене важна, чем при загрузке. Также есть три идеи для оптимизации:
- Здесь можно избавиться от вызова функций count:
if r.suck(1, 64) then local rep = r.count(1)
В документации сказано, что метод suck() возвращает значение типа boolean, но это не совсем так. В случае неудачи suck() вернёт false, а в случае успеха вернёт количество предметов.
- В каждой итерации цикла заново считывается размер инвентаря робота:
while true do ... for i=1, r.inventorySize() do
Это, конечно, экономит одну переменную, но память не экономит всё равно. Зато немного нагружает процесср. Считывание размера инвентаря в каждой итерации цикла имеет смысл только для роботов, оснащённых съёмными апгрейдами инвентаря.
- А эта строчка, по-моему, вообще лишняя
r.select(1)
Я не вижу особого смысла загружать предметы именно в первый слот. Может быть, если бы размер инвентаря робота превышал 16 слотов, то игроку было бы удобно визуально контролировать процесс работы программы. Но это, похоже, не тот случай. Только лишняя нагрузка на сервер.
-
1 час назад, Bs0Dd сказал:Сделал паузу по функции из ОС
Да, так вернее. Но всё равно не надо спешить и тупо копировать код:
local ws = computer.uptime() repeat computer.pullSignal(ws - computer.uptime()) until computer.uptime() >= ws
Зачем в скопированном куске оставлять код цикла, зная, что тот выполнится ровно один раз?
Зачем в скопированном куске оставлять код получения текущего времени, зная, что параметром функции computer.pullSignanl всегда будет ноль?
Все эти лишние действия не бесплатны, они повышают нагрузку на игровой сервер.
-
20 минут назад, Zer0Galaxy сказал:Почему бы не сделать так?
while computer.pullSignal(5) do;В этом случае робот очистит очередь сигналов прежде чем начать отсчет таймаута.
Можно сделать и так, если учесть, что при такой реализации пауза после переработки полного стака предметов будет равна не 5, а 8.2 секунды.
-
33 минуты назад, Bs0Dd сказал:Пауза в конце тут стоит, сколь я понял, на тот случай, если в сундуке вдруг кончатся ресурсы. Тогда робот будет ждать 5 секунд перед следующей попыткой взять оттуда блок. И если уже есть ивенты и пауза не произойдет, то он опять попытается взять блоки, поймет, что их нет и снова пойдет в ожидание на 5 сек.
Да, пауза стоит на тот случай, если кончится ресурсы, и для того, чтобы не создавать бесполезную нагрузку на сервер. Но в текущей реалзиации, прежде чем выполнится пауза, робот попытается взять блоки 255 раз. А это противоречит цели, ради которой в программу добавлена пауза.
41 минуту назад, Bs0Dd сказал:Но вообще в такой конструкции, как я говорил, сбив паузы не критичен. Задержка в 5 сек все равно работает (ибо робот берет блоки не сразу после их закидывания в сундук), проверял перед правкой в паст
Это уже зависит от критериев критичности. Для чего именно не критичен сбой паузы? Для нагрузки на сервер? Так нагрузка обычно и складывается из таких мелочей, когда программа продолжает что-то делать, когда делать уже ничего не требуется.
Да, задержка в 5 секунд всё равно сработает, рано или поздно. Тут я согласен. Я поспешил со своим категоричным заявлением. Был не прав. Переформулирую. Задержка почти никогда не выполнится сразу после рубки очередного стака блоков. В большинстве случаев задержка в 5 секунд выполнится лишь после 255 неудачных попыток получить блоки из сундука.
-
Я ещё раз посмотрел код. Там после computer.pullSignal(0) следуют вызовы r.drop(0, 64).
Соответственно, даже если произошло везение в предыдущей части кода, и очередь сигналов каким-то образом очистилась, то успешное выполнение robot.drop() снова поставит сигнал очистки слота робота в очередь событий.
Итог: пауза не будет выполнена почти никогда.
-
45 минут назад, Bs0Dd сказал:Убрал нарезки из библиотеки в коде и заменил на него, вроде все работает.
Каких прекрасных результатов можно достичь, если не спешить, и немного подумать! Но я предлагаю дополнительно поразмыслить.
Казалось бы, в таком примитивном роботе попросту отсутствуют компоненты, которые бы могли генерировать сигналы. Тем не менее, генерируются сигналы при появлении или исчезновении предметов в инвентаре робота. При этом никто не забирает их из очереди событий. Теоретически, это могло бы происходить при вызове computer.pullSignal(0), но он выполняется только при неудачных попытках срубить блок, а значит, нечасто.
К моменту вызова computer.pullSignal(5) очередь событий окажется, скорее всего, непустой. И попытка взять паузу окажется неудачной.
-
1 час назад, Bs0Dd сказал:Если нужно сэкономить на производстве роботов, то могу предложить немного переработанную версию (сделанную за пару минут на коленке) на основе той же программы от Asior'а: https://pastebin.com/gdk0by50
За первую попытку, конечно же, лайк. Но всё же, не стоило так бездумно копировать код из стандартной библиотеки. Там же достаточно было несколько строк всего вытащить.
-
В 07.12.2020 в 19:57, serafim сказал:добавил динамический список недостающих компонентов в инвентаре робота
Если дописать короткую инструкцию, как игроку обращаться с этой программой, и чего с ней делать нельзя, то можно и остановиться на этом.
@demongts1998 протестируй эту версию. Она не идеальна, но вполне годная. Можно было бы немного снизить нагрузку на сервер, но на скорости заполнения реактора это существенным образом не отразится. Можно было бы сделать алгоритм более устойчивым к кривым рукам пользователей, но это потребует существенных усилий от программиста, проще написать инструкцию. Тем более, в условиях заказа не сказано, до какого состояния следует допиливать. Я считаю, допилено хорошо.
-
В 07.12.2020 в 00:37, demongts1998 сказал:ввели крафт за донат валюту, которую можно получить по 30 в день ( крафт стоит 60 )
Раз ценность роботов так повысилась, то, может быть, стоит использовать схему на одном роботе? Благодаря этом робот быстрее отработает свою цену.
При желании можно установить четыре таких робота вокруг одного зарядника.
-
2 часа назад, hohserg сказал:если нельзя не строить очень много реакторов, то лучше полностью автоматизировать процесс, потому что это гринд, а не интересная игра
Судя по тому, что я узнал в темах этого заказа и заказа про переработку руды, администраторы обсуждаемого сервера склоняют игроков именно к гринду. Что мы имеем:
- Ценность материалов на строительство реакторов и их компонентов настолько мала, а ценность энергии настолько велика, что игроки готовы строить по 324 реактора и обслуживать их даже без особой автоматизации.
- Мы слышим заявление от информированного человека о том, что причиной низкого TPS на сервере является большое количество реакторов. Но вместо снижения ценности энергии или дополнительно ограничения количества именно реакторов, администрация ввела крафт роботов за донат-валюту.
Другое дело, что считают интересным сами игроки этого сервера. Поэтому вопросы к @demongts1998:
- Ты получаешь удовольствие от расстановки 324 реакторов вручную?
- Интересно ли тебе использовать робота, который сам расставит реакторы, или всё-таки ручная расстановка более предпочтительна?
- Целесообразна ли на этом сервере полная автоматизация, в которой роботы сами строят реакторы и обслуживают их? Или такая программа будет работать до ближайшего вайпа, и весь процесс снова скатится в тупой гринд, а к тому же ещё и роботы будут снова понерфлены? Какой сценарий ты считаешь наиболее вероятным?
2 часа назад, hohserg сказал:Существует ли схема для обычного реактора, которая бы позволяла тратить топливо и генерировать энергию в 100 раз быстрее?
При низкой ценности материалов выгодны схемы на конденсаторах. Только они обеспечивают максимально плотное заполнение реактора топливом. Но именно эти схемы требуют активного перемещения реакторных компонентов между инвентарями и постоянного ремонта конденсаторов, что, конечно же, тоже вносит свой вклад в снижение TPS. Такие схемы обсуждались в заказе Программа "Очень много электричества". Это, конечно, не в 100 раз выше, а раз в 10. Но дальше могут возникать и другие препятствия из-за ограничения мода и аддонов: при определённых их сочетаниях производство энергии из MOX-топлива одним реактором может превышать возможности самого мощного потребителя, MFSU и самые лучшие кабели могут взрываться, или реактор может просто не выдать энергию свыше 16384 eu/t.
-
1
-
17 минут назад, demongts1998 сказал:интересно, интересно, пока что на сервере решаем проблему крафта роботов, будем решать что как делать
А крафт роботов стал проблемой?
-
14 минуты назад, serafim сказал:мене тоже смущает этот вопрос, очень часто робот в привате имеет ограничения и robot.drop() предпочтительней
Возможно, так и надо будет оставить, чтобы сделать программу программу более универсальной. Тогда имеет смысл использовать другое преимущество текущего решения. Т.к. мы сейчас всё равно заранее сканируем инвентарь, это даёт возможность сообщать игроку список недостающих компонентов ещё до начала заполнения реактора. И в те секунд 30, пока робот выкладывает компоненты, игрок может успеть сбегать за дополнительными, уже точно зная, каких именно компонентов не хватает.
-
48 минут назад, serafim сказал:Насчёт что через robot.count(slot) быстрее, как то не замечал, ок учту
Я рассказывал на днях о методике измерений. За время выполнения getStackInInternalSlot (один тик) можно 1000 раз выполнить robot.count. При одиночном выполнении это, конечно, заметить трудно. Но при сканировании 64 пустых слотов робота будет заметно даже на глаз.
54 минуты назад, serafim сказал:да так ещё лучше, может сделаю
Да, так сильно проще. Если не требуется заблаговременно уведомлять игрока об отсутствии ресурсов, то мы просто последовательно сканируем слоты робота и при обнаружении компонента проверяем, есть ли в реакторе слот, ожидающий именно этот компонент, и сразу переносим. Вместо таблицы содержимого инвентаря робота ведём таблицу ещё незаполненных слотов реактора. Завершив сканирование инвентаря робота и перенос, проверяем таблицу и выводим список недостающих компонентов. В сравнении с текущим вариантом для игрока не сильно что-то изменится. В целом, игрок будет получать уведомление о недостающих компонентах позже, но зато все уведомления сразу.
1 час назад, serafim сказал:в таком случае придётся повторно запрашивать имя компонента тратя кучу времени
Тут вариантов не особо много: либо тратить время на дополнительные запросы, либо аккуратно обрабатывать сигнал изменения слота, либо в инструкции пользователя прописывать запрет на некоторые манипуляции в процессе работы.
-
18 часов назад, serafim сказал:Можете потестить установщик схемы в реактор IC2 https://pastebin.com/xWhYcrgM
До тестирования я не добрался, но почитал код. Есть замечания и вопросы:
- Функцию сканирования инвентаря можно немного ускорить, отказавшись от выполнения getStackInInternalSlot(slot) для заведомо пустых ячеек. Наличие предмета в слоте помогает определить функция robot.count(slot), и работает она очень быстро. И только уже зная, что слот не пуст, появляется смысл запрашивать getStackInInternalSlot(slot). В остальных случаях получаем экономию в один тик на каждый пустой слот.
- robot.inventorySize() вызывается больше одного раза, каждый раз тратя на это один тик времени. Такое решение полезно для случая съёмных апргейдов инвентаря. Но удобнее всё же сделать несъемные. Тем более, автор заказа не ограничен в материалах. Ему под силу сразу скрафтить нужного робота.
- При поступлении сигнала inventory_changed программа заново сканирует инвентарь, тратя на это 3.2 сек при 64 слотах в инвентаре робота, хотя достаточно обработать лишь те слоты, для которых поступил сигнал изменения.
- При обнаружении отсутствующего компонента в инвентаре робота необязательно тратить время только лишь на ожидание его появления. Достаточно сообщить игроку список отсутствующих компонентов и продолжать заполнение, возвращаясь к пропущенным слотам позже. У на же есть контроллер инвентаря, поэтому вместо robot.drop() можно использовать component.inventory_controller.dropIntoSlot(side,slot,count), помещая предмет строго в нужный слот. Или на сервере какие-то особенности приватов не позволяют так обращаться с внешними инвентарями?
- Если использовать dropIntoSlot допустимо, то заранее сканировать инвентарь робота имеет смысл только для того, чтобы сообщить об отсутствующих игроку компонентах. А если сообщение игроку поступает ровно в момент попытки поместить компонент в реактор, то и сканировать слот инвентаря можно непосредственно перед этим.
- Обнаружение изменения инвентаря сейчас реализовано проверкой на 0 значения robot.count(slot). Это работает только для случая извлечения предмета из слота. Но игрок может произвести замену предмета. В этом случае программа рискует поместить в реактор не тот компонент.
- Зачем функция set сделана рекурсивной? В чём удобство именно рекурсивной функции?
-
1
-
1 минуту назад, serafim сказал:можно проверять перед отправкой в реактор если ли компонент в инвентаре от предыдущего скана
Для полной уверенности придётся проверять и статус операции отправки в реактор, а сразу после отправки вдобавок ещё проверить, не поступили ли за это время какие-то лишние события по этому слоту. Или можно тупо проверить нужный слот в инвентаре реактора. Это, конечно, немного замедлит работу, но обеспечит полную устойчивость алгоритма без его сильного усложнения.
-
1
-
-
1 час назад, serafim сказал:Прога как то не адекватно реагирует на событие inventory_changed
хотя должна реагировать только если в инвентарь что-то добавили а не забрали
Сигнал inventory_changed генерируется в случаях изменения предмета в инвентаре: в пустом слоте появился предмет; предмет исчез из слота; предмет в слоте был заменён другим. Оно не возникает лишь при изменении количества предмета в слоте.
Логично, что программа должна уметь обрабатывать все три ситуации. Даже если мы в какой-то таблице хранили количество предметов в слотах инвентаря робота, то без дополнительных вычислений однозначно идентифицировать мы сможем только ситуацию появления предмета в слоте. А отличить исчезновение предмета в слоте от его замены можно, например, анализируя значение robot.count() при получении сигнала.
Есть ещё один нюанс. Робот настолько медлителен, что за время, пока он перекладывает предмет, игрок может изменить состояние одного слота несколько раз. Поэтому накопившиеся события следует обрабатывать сразу пачкой, а не по одному. А перед чтением информации о предмете и отправкой его в реактор надо проверять, не прилетело ли очередное событие по этому слоту.
Так как алгоритм обработки inventory_changed рискует сильно усложниться, то можно просто написать в инструкции пользователя, что если игрок извлекает предметы из инвентаря робота в процессе загрузки компонентов в реактор, то правильность работы программы не гарантируется.
-
1 час назад, hohserg сказал:Как были произведены такие точные измерения?
Для начала рекомендую почитать об отличиях прямых вызовов от непрямых. Статья полезная, но даже если не знать теорию и названия, всегда можно обнаружить закономерности экспериментальным путём. И я сейчас попробую это продемонстрировать.
Есть функция computer.uptime(), она возвращает время работы компьютера в секундах. Но время всегда пропорционально одному тику. Вычисляя разницу во времени, прошедшем от начала и до конца измерений, можно измерить скорость выполнения операций. Грубо, в тиках, но можно.
Выполняя операции массово, в цикле, можно обнаружить, что некоторые операции всегда требуют целого количества тиков. Количество затрачиваемых тиков на некоторую определённую операцию всегда одинаково, и может задаваться в файле конфигурации. Это непрямые вызовы, и они замедлены намеренно. Также можно заметить, что во время лагов не только сервер снижает TPS ниже стандартных 20, но и вызовы периферии могут выполняться за большее количество тиков в сравнении с заданными значениями.
Также существуют вызовы прямые. Они не отличаются от вызова обычных функций, и время затрачиваемое на их выполнение, очень мало. Какого-то фиксированного времени для их выполнения не существует. Время определяется быстродействием сервера и его текущей нагрузкой.
А ещё есть не особо прямые вызовы. По терминологии, наверное, может проконсультировать @Fingercomp. Время, затрачиваемое на эти вызовы, не кратно размеру тика, но количество таких вызовах на протяжении тика ограничено некоторыми предельными значениями.
Теперь практика.
По счастливому стечению обстоятельств я не закрыл документ с текущими записями по этой теме. Записи такого вида я обычно не сохраняю в файлы, а веду их только для удобства вставки скриптов в консоль робота.
Текущее содержимое документа (комментарии добавлены сейчас):
-- Ссылка на получение времени time=computer.uptime -- Тестирование затрат времени на установку блока и его рубку -- Я уже знаю, что это непрямые вызовы, поэтому не использую сложных измерений -- Для исклчюения влияния случайных лагов повторяю выполнение скрипта раза три t0=time() robot.place() print(time()-t0) t0=time() robot.swing() print(time()-t0) -- Это пробная версия скрипта, рубящего руду -- Именно этот скрипт я выкладывал где-то в ранних постах этой темы t0=time() robot.select(1)while robot.suckUp() do for i=1,64 do robot.place()robot.swing()end for slot=4,1,-1 do robot.select(slot)robot.dropDown()end end print(time()-t0) -- Тут я проверял алгоритм выгрузки результатов переработки for slot=4,1,-1 do robot.select(slot)robot.dropDown()end -- Так я обычно пишу несложные программы -- Ничего не сохраняю в файлы, пишу скрипт в текстовом редакторе, -- а потом сворачиваю до одной строки для удобства копирования в консоль робота -- Самые простые скрипты сразу пишутся в одну строку ---------- рубщик руды time = computer.uptime while not robot.detect() do end t0=time() for i=1,64 do while not robot.swing() do end end print( time()-t0 ) time = computer.uptime while not robot.detect() do end t0=time() for i=1,64 do while not robot.swing() do end end print( time()-t0 ) ---------- установщик руды time = computer.uptime t0=time() for i=1,64 do while not robot.place() do end end print( time()-t0 ) time = computer.uptime t0=time() for i=1,64 do while not robot.place() do end end print( time()-t0 ) ---------- -- Похоже, вызов robot.count непрямой, операция заняла 0 тиков t0=time() robot.count(1) print(time()-t0) -- И сейчас 0 тиков t0=time() for i=1,1e2 do robot.count(1) end print(time()-t0) -- А сейчас 1 тик t0=time() for i=1,1e3 do robot.count(1) end print(time()-t0) -- Ну, ясно, быстрая операция. -- А как быстро выполняется выбор слота в роботе? t0=time() robot.select(1) print(time()-t0) -- И т.д... t0=time() robot.drop() print(time()-t0) t0=time() component.inventory_controller.getStackInInternalSlot(1) print(time()-t0)
Полученная разница во времени не всегда кратна ровно размеру тика по причине погрешности вычислений. Но округление решает эту проблему. Для полной ясности можно сразу считать целые тики:
print( ((time()-t0)/0.05+0.5)//1 )
Но мне обычно лень писать такой код во время разовых исследований. Да и есть шанс пропустить какое-то значимое расхождение с размером тика, превышающее погрешность вычислений. В программах я обычно использую что-то вроде такого:
(dt*1e6+0.5)//1/1e6
-
1
-

Доработка программы для переработки руды
в Новые заказы
Опубликовано:
@serafim Хороший анализ плохого кода, я согласен почти с каждым утверждением. Но в удалении этой темы я не вижу смысла. В ней разобраны альтернативные варианты решения поставленной задачи, более экономно расходующие ресурсы сервера.
Обсуждение проблемы лагодромов я считаю полезным. Большинство игроков создаёт лагодромы ненамеренно, т.к. попросту не знает, как писать программы правильно, как минимизировать нагрузку на сервер. Таким игрокам будет полезна информация о том, как решить задачу правильно. А тот, кто вредит серверу целенаправленно, готов использовать для этого любые другие моды, а не только OC. И останавливает такого игрока только одно средство — бан.
Конечно же, не стоит выкладывать готовые скрипты для причинения вреда серверу. Но также не стоит и препятствовать обсуждению плохо спроектированного кода из опасений, что оно будет содержать намёки на возможность создания явно вредоносных программ. Под этим предлогом можно было бы удалить многие темы нашего форума. Но что нам это даст?