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

Лидеры


Популярный контент

Показан контент с высокой репутацией за 10.01.2015 во всех областях

  1. 21 балл
    Как собрать робота в 5 шагов (инструкция для самых маленьких) Абстрактное описание сборки робота я уже писал много раз, поэтому это будет короткое руководство на конкретном примере. Соберем и запустим Totoro Recursive Miner. Шаг 1. Подготовка Для создания робота нам потребуется сборщик (assembler). Чтобы он работал - подведите питание. Сборка робота потребует некоторого времени (примерно 5 минут) и энергозатрат. Шаг 2. Подбор железа Запчасти делятся на обязательные и необязательные. Детали обязательные: 1) Корпус Основа робота. Без него никуда. Для TRMiner нужен корпус 2+ уровня, потому что он должен содержать апгрейд-генератор. 2) Процессор Мощность процессора определяет количество выполняемых роботом операций в такт. Т.е. проще говоря - скорость его работы. Однако перемещаться быстрее робот не станет. Этот параметр можно улучшить "прокачав" робота (см. апгрейд-опыт). 3) Память Практика показала, что одной планки 1 уровня для нормальной работы на компьютере недостаточно. TRMiner хранит в памяти данные о жилах руды, поэтому требует как минимум две планки уровня 1.5. При меньшем количестве корректную работу не гарантирую. (Хотя возможно он будет работать.) 4) Монитор Достаточно 1 уровня. Робот не поддерживает цветные экраны. (Можно собрать робота и без экрана. Но это - для любителей хардкора.) 5) Видеокарта Также достаточно 1-го уровня. Требуется для вывода изображения на монитор. Без нее монитор будет просто черным. 6) Клавиатура Чтобы иметь возможность набрать что-то в консоли. 7) Дисковод Для установки OpenOS и копирования программы TRMiner. (Любители хардкора могут попробовать запустить робота без дисковода. Это возможно. Но я не скажу как :P ) 8) Жесткий диск Для хранения ОСи и программы. Первоэтапный диск в 1Мб хватит с головой. Это даже много. Будет занято ~20%. 9) Lua BIOS Этот чип нужен для корректной работы OpenOS. Крафтится из пустого EERPOM и книги. Детали обязательные для Totoro Recursive Miner: 10) Апгрейд-инвентарь. Робот хранит в нем добытую руду. Рекомендуется установить 2 или 3 апгрейда (т.е. 32 или 48 слотов). Больше можно не ставить, ибо обычный сундук, в который робот сбрасывает добычу имеет размер в 27 слотов. 11) Апгрейд-генератор. Нужен роботу для непрерывной работы. Робот будет сам заряжаться с его помощью, сжигая часть добытого угля. (Любители хардкора могу не ставить генератор. Программа будет работать. Вы можете заряжать робот таская за ним заряжающее устройство, или приделав пару солнечных панелей и выкопав вертикальный колодец до поверхности. ) Детали необязательные: 12) Апгрейд-опыт Позволит роботу прокачиваться во время добычи. Со временем он станет быстрее двигаться, меньше тратить энергию и медленнее ломать свой инструмент. Требует Корпуса 3-его уровня. 13) Апгрейд-батарея Ну тут все понятно. Увеличивает емкость аккумулятора. Полезная штука. Детали вредные (эксклюзив для IT 1.7.10): 14) Апгрейд-чанклоадер После включения робота, в момент опустошит его аккумулятор. На том все и закончится. Вот две рабочие конфигурации: Минимальная Рекомендуемая (UPD.: Тут уважаемый Krutoy любезно предоставил картинку, которая иллюстрирует, сколько всего ресурсов у вас уйдет на сборку рекомендуемой конфигурации робота: За что ему большое спасибо.) Уложите выбранные детали в сборщик и запускайте процесс. Шаг 3. Софт Раздобудьте дискету с OpenOS (крафтится из чистой дискеты и книги). Скачайте программу Totoro Recursive Miner на другую, чистую дискету. http://pastebin.com/L21VMm7S Для этого этапа нам потребуется компьютер. Свой или соседа, все равно. Он должен иметь выход в интернет (интернет-плата) и дисковод для дискет. Как скачать программу на новую дискету: 1) Вставить дискету 2) Посмотреть в инвентаре ее адрес. Запомнить первые его буквы-цифры. 3) Написать в консоли команду: label -a xxxx floppy Где xxxx - первые буквы-цифры ее адреса, а floppy - это будущее название (этикетка). В результате ваша дискета получит короткое и ясное название. 4) Написать команды: mount floppy fcd /f В результате вы окажетесь в корневом каталоге дискеты. 5) Скачать программу TRMiner: pastebin get L21VMm7S mine Для этого нужна интернет-плата. Программа будет сохранена на дискету под именем mine. 6) Извлеките дискету. (Также можно поискать игрока с ником Totoro и подоставать его, чтобы дал дискету с программой нахаляву. Тогда и компьютер не нужен.) Шаг 4. Установка Поставьте робота. Можно прямо на месте предполагаемой добычи руды. Чтоб два раза не ходить. Включите его и установите OpenOS (это надо сделать только один раз). Как установить OpenOS: 1) Вставить в робота зеленую дискету. 2) Включить его. 3) Написать в консоли: install 4) Он спросит на какой жесткий диск устанавливать. Напишите 1. 5) Согласитесь на рестарт (y). Теперь сбросьте программу TRMiner с дискеты на жесткий диск робота. (Можно каждый раз вставлять дискету и запускать программу прямо с нее, но это лишние действия. Зачем оно нам?) Как сбросить программу с дискеты: 1) Вставить дискету с программой в робота. 2) Убедиться, что он включен. 3) Написать в консоли робота: mount floppy fcp f/mine mine 4) Достать дискету. Все! Софт установлен. Дискеты больше в принципе не нужны. Но сохраните их на всякий случай. Шаг 4A. Настройка программы (необязательно) Для настройки программы Totoro Recursive Miner, введите в консоль команду: edit mine В двадцатой строке вы увидите константы набранные заглавными буквами: TECH_SLOTS = 6VANILLA_CHEST = truePATHWAYS = trueDROP_TRASH = false TECH_SLOTS - количество слотов с образцами "пустой породы" и сундуками. То есть тех слотов, которые не будут заняты добычей. VANILLA_CHEST - режим для работы с обычными сундуками. Есть возможность работать с сундуком Эндера. Для этого, установите константу в значение false и дайте роботу инструмент с зачарованием "Шелковое касание". В слот с сундуками положите один сундук Эндера. PATHWAYS - если true, робот проделает в шахте дорожки, для удобства хождения игрока DROP_TRASH - если true, робот будет выбрасывать булыжник и другую "пустую породу". После изменения констант, нажмите клавиши Ctrl+S (сохранение) и Ctrl+W (выход). Шаг 5. Добыча полезных ископаемых Принесите робота на место предполагаемой шахты. Поставьте робота в ее воображаемый правый передний угол, передней стороной вперед. Вот так: В инвентаре робота разложите образцы пустой породы (5 штук по дефолту). Причем (лайфхак для ускорения работы робота), кладите в порядке убывания распространенности. У меня это камень-земля-гравий-булыжник-камень Бездны (abyssal stone из RailCraft). В последний из технических слотов (6-ой по дефолту) положите сундуки (или сундук Эндера, если вы перенастроили программу). Роботу в "руку" положите кирку или бур. Чем прочнее и острее - тем лучше. Теперь включите. Введите в консоль команду такого формата: mine <длина> [ширина] [возвращаться_в_начало] Первые два параметра - числовые. Последний - true/false (Если не указать, равен false). Ура! Наконец все ездит, копает и складывает без нашего участия. Остается только иногда менять кирку. И уносить добычу. Enjoy!
  2. 15 баллов
    Ну что ж. Буквально на днях майнось наконец релизнулась в виде полностью самостоятельной и независимой от OpenOS операционки с собственным набором библиотек и вики. Все родное, отечественное (звучит как диагноз). Большинство методов библиотек по типу filesystem или keyboard крайне схожи с таковыми в опеноси по поведению, так что особых проблем с переходом возникать не должно. Также существенно снизился расход оперативной памяти - примерно на 7% от 4 планок 3 уровня. Осталось, конечно, регулярно выискивать мелкие недочеты и допиливать их, а также более подробно наполнять инфу на вики, но в целом результатом я доволен. Среди ключевых нововведений стоит отметить следующие: Полностью переписанный инсталлер, запускающийся даже с EEPROM, имеющий возможность выбора тома для установки и его форматирования, а также систему конфигурации пользовательского профиля. Добавлено несколько системных языков, а заодно возможность установки лишь выбранного языкового пакета вместо всех сразу для экономии места на диске: Полная двойная буферизация графики, все приложения переписаны под библиотеку GUI. Кстати, местный картинко-редактор заимел оконный режим, а также Ёлочка @Totoro стала отлично работать в фоне и украшать хату (в моем случае - жалкий клочок земли в воздухе): Крайне полезный режим Internet Recovery, позволяющий мгновенно переустановить систему напрямую из EEPROM в случае возникновения каких-либо проблем: Возможность заливки файлов напрямую на Pastebin буквально парой кликов: Фича создания ассоциаций расширений файлов с возможностью назначения приложения для открытия того или иного расширения:
  3. 15 баллов
    Дроны - как керосин. Они есть везде. Еще года два назад это было просто еще одно интересное видео на Ютубе. Год назад они вдруг оказались в интернет магазинах. Затем просочились в рекламу на ТВ, и вот теперь - они есть и в OpenComputers! Пришла пора с ними разобраться. 1. Матчасть Дрон, в данном случае - квадрокоптер, это беспилотный летающий аппарат, приводимый в движение двумя парами горизонтальных винтов. Приостановливая вращение винтов с одного боку, дрон двигается в сторону (стрейф). Эти винты вращаются в разном направлении (два - по часовой срелке и два - против), за счет чего дрон не нуждается в стабилизирующем хвостовом пропеллере (как вертолет). За счет этого же он и разворачивается в воздухе, замедлив вращение однонаправленной пары винтов. Дрон обладает небольшой массой, для экономии энергии, которой у него не много (на 10-30 минут полета в среднем). (с) Википедия 2. Дроны и OpenComputers Приблизительное изображение дрона в OpenComputers =): В мире Майнкрафта дрон представляет из себя "сущность" (Entity). Это значит, что он обладает возможностями мобов Майнкрафта. (В то время как робот - это блок.) Его можно сдвинуть с места толкая. Он умеет пролетать сквозь двери и калитки (в отличии от робота). Он движется не последовательно, из блока в блок, а из точки в точку. Причем маршрут может лежать по диагонали. Конечно, движется он по кратчайшей линии, и если на пути окажется стена - дрон столкнется с нею. Программирование дрона как две капли воды похоже на программирование микроконтроллера. Вы точно так же записываете программу на EEPROM, и при необходимости меняете ее на верстаке. Только в отличии от контроллера, вам становится доступен новый компонент: drone. Подробнее об командах дрона можно узнать здесь: OpenComputers/Дрон. (Или здесь: ocdoc.wiki (англ.)) 3. План Нужна какая-нибудь несложная задача, для целей эксперимента. Используем программку send из предыдущего поста, для удаленного управления. Зальем ее на планшет. А дрон пусть... носит свиней. Будем оригинальными и непоследовательными. 1. Команда 'add X Y Z Name From'. Добавляем точку Name к маршруту, цепляя ее к точке From. Зададим дрону последовательность точек, которые образуют граф - безопасные маршруты. 2. Команда 'catch' - дрон ловит свинью. 3. Команда 'drop' - дрон выпускает свинью. 4. Команда 'to X' - дрон летит в точку Х. Для начала не будем особо заморачиваться с графом маршрутов. Это будет простое неориентированное дерево. Примерно такое: 4. Строим полигон Построим что-нибудь подходящее для тестов. Отметим ключевые точки будущего графа красными блоками. А синий блок - будет стартовой площадкой дрона. Поскольку я играю без модов на энергию, мой планшет и дрон будут работать вечно. И я не заморачиваюсь станцией подзарядки. Иначе, к схеме выше было бы необходимо добавить станцию, где дрон мог бы зарядить аккумулятор. 5. Пишем программу Скрипт для удаленного управления скопипастим из прошлого поста, подправим, чтобы умела отправлять несколько переменных и зальем на планшетик, для удобства. (Для этого, соберите планшет - не забудьте клавиатуру и видеокарту! - положите его в зарядник и запустите с подключенного компа команду install. Укажите адрес винчестера планшета - и все, что было у вас на компе автоматически загрузится в планшет, включая даже ваши собственные программы.) local com = require('component')local modem = com.modemlocal args = {...}modem.broadcast(27, table.unpack(args))io.write("Message: ")print(table.unpack(args)) Далее - более сложная часть. Программа дрона. Программа предназначена для EEPROM. Значит соблюдаем те же правила: используем computer, component и API имеющихся у дрона компонентов. Включая его родной компонент drone. В нашем случае, дрон вооружен апргейдом-лассо (leash) и беспроводной сетевой картой (modem) для связи. Стоит отметить, что процесс отладки программы (по крайней мере в текущем билде мода) достаточно неудобен. В случае ошибки дрон отказывается включиться, издав тонкий писк, и не выводя никакой информации. Получить отчет об ошибке при помощи анализатора не выйдет - ведь Shift+ПКМ просто снимает дрона. Автор обещал в скором времени это исправить. Ну а пока - помучаемся. Отредактировать чип в стороннем редакторе, не вынимая его из дрона тоже не выйдет. В отличии от файловых систем, которые имеют удобную папку вида /saves/World/opencomputers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/, чипы EEPROM хранят свой код в NBT тегах предмета. Этим же обусловлено и ограничение размера кода в 4 килобайта. 5.1. Основная часть Это цикл который ждет указаний, а затем запускает соответствующую функцию. drone = component.proxy(component.list("drone")())modem = component.proxy(component.list("modem")())leash = component.proxy(component.list("leash")())modem.open(27)route = {}path = {}current = ""while true do name, _, sender, _, _, message, x, y, z, point, from = computer.pullSignal(1) if name == "modem_message" then if message == 'add' then add(tonumber(x), tonumber(y), tonumber(z), point, from) if current == "" then current = point end elseif message == 'to' then to(x) elseif message == 'catch' then catch() elseif message == 'drop' then drop() end end if #path > 0 and drone.getOffset() < 1 then drone.move(route[path[#path]].x-route[current].x, route[path[#path]].y-route[current].y, route[path[#path]].z-route[current].z) current = path[#path] path[#path] = nil endendmodem.close() Чтобы облегчить себе жизнь (и тестирование bios), вы можете сделать так: напишите заглушку для компонента drone (и других, если надо), вроде этой: http://pastebin.com/EVYzN5Bj Просто скопируйте в папку на компьютере, где вы пишете программу для дрона. Затем измените первые строки программы следующим образом: component = require('component')computer = require('computer')drone = require('drone')modem = component.modem-- leash = component.proxy(component.list("leash")()) Затем добавьте в цикл условие выхода по нажатию кнопки: if name == 'key_down' then break end И вы можете просто запустить вашу программу для дрона на компьютере. Разумеется полноценной эмуляцией дрона тут и не пахнет, зато очень удобно отслеживать глупые синтаксические и логические ошибки. Как устроен код основного цикла? Переменная route - хранит таблицу "вейпоинтов" (waypoints). Это вершины графа и информация о связях между ними. Переменная path - хранит путь от текущей вершины до цели. Переменная current - отмечает текущее местоположение дрона в графе. В цикле мы читаем получаемые сообщения и вызываем соответствующие функции. Первая переданная вершина считается дроном текущей. Во второй части цикла происходит проверка. Если путь до цели - не пуст (это значит, что дрону надо куда-то лететь) и дрон уже долетел до текущей вершины (getOffset()), то программа берет следующую вершину из path, отправляет дрона к ней и объявляет ее текущей. 5.2. Функции-команды Теперь последовательно добавим функции для каждой команды. function add(x, y, z, name, from) route[name] = {x=x, y=y, z=z, link = {}} if from ~= nil then if route[name] == nil or route[from] == nil then drone.setStatusText("Error!") else table.insert(route[name].link, from) table.insert(route[from].link, name) end endend Тут все просто. Пишем вершину в список. Если он связана с другой вершиной (from ~= nil), то в специальную табличку link заносим две связи: из name в from, и из from в name. function search(target, point, prev) for key, name in pairs(route[point].link) do if name == target then table.insert(path, point) return true end end for key, name in pairs(route[point].link) do if name ~= prev then if search(target, name, point) then table.insert(path, point) return true end end end return falseendfunction to(name) path = {} table.insert(path, name) search(name, current)end Функция to обнуляет старый путь (на всякий случай), затем вставляет в него цель пути (name) и запускает функцию search, которая рекурсивно ищет и записывает остальные промежуточные вершины на маршруте от name до current (текущей локации). Функция search сделана достаточно примитивно (возможно вы предложите более эффективный способ?). Поскольку мы договорились, в целях упрощения использовать граф-дерево (не содержаший петель), от любой точки к другой существует один и только один маршрут, который функция и находит перебором связанных вершин. function catch() for c = 2, 5 do if leash.leash(c) then return true end end return falseendfunction drop() leash.unleash()end Тут все элементарно. 6. Подготовка Пишем программу на дрона, заряжаем планшет и выдвигаемся в зону действий. Дрона ставим на синий куб (стартовая площадка) и включаем. После уточнения на местности, составляем карту вейпоинтов и строим на бумажке будущий граф: Для каждого загона добавлены две точки - name и name_up. Основные "трассы" дрона лежат на высоте в 6 блоков. А в каждом загоне спускаются к земле. (Чтобы заарканить животное, выстреливая лассо вбок, дрону желательно находиться на одном уровне с жертвой). С планшета вносим координаты в память дрона. Примерно так: Главное - не ошибиться. Т.к. в код не была добавлена защита "от дурака" =) Алгоритм позволяет добавлять вершину "на лету". В любой момент вы можете добавить еще одну ветку к схеме. Теперь все готово к тесту. 7. Запуск Все готово. Проверим, как он двигается. Введем send to sheeps в консоль планшета. Дрон уверенно поднимается в воздух и опускается в загоне в овцами. Теперь введем send to pigs. Функция search снова вычислит путь и робот переместится в указанную вершину: Функции catch и drop тоже работают штатно =) Хотя и не лишены некоторых глюков (ведь физика веревки не просчитывается): 8. Итоги а) Дрон - любопытная штуковина. б) Полный код прошивки. использованный в этом посте - здесь: http://pastebin.com/Cy1UR6vy в) Навигация по вейпоинтам - интересный и очень распространенный способ организации сложного движения. Схему можно усложнить - опционально добавлять только одну связь в таблицу link - тогда получатся ребра с односторонним движением. Добавить петли, оптимизировать поиск кратчайшего пути. Еще можно облегчить правление дроном - хранить все команды для конкретной задачи в виде файла-скрипта, который запускать одной командой и т.д. Enjoy!
  4. 12 баллов
    Трехмерная печать в Minecraft (инструкции для самых маленьких) Начиная с версии 1.5.4, в OpenComputers появляется интересный девайс - трехмерный принтер. Он дает возможность печатать декоративные блоки любой формы и цвета. Причем не только статичные блоки, но и двери/люки, кнопки и рычаги! Давайте рассмотрим, для чего он может пригодиться, и как именно с ним работать. 1. Цель Как и в предыдущих гайдах, первым делом поставим себе цель. Мы будем создавать стенную плитку со сквозным орнаментом, в виде морды крипера. Я не буду приводить в этом гайде рецепты предметов, так как их легко найти в NEI, или в статьях на gamepedia. 2. Обзор принтера 3D-принтер - это периферическое устройство, которое должно быть подключено к работающему компьютеру. Оно представляет собой блок, с двумя внутренними слотами: Верхний слот предназначен для специальной печатной массы (изготовляется из редстоуна, гравия, древесного угля и воды). Принтер вмещает два стека печатной массы (256 000 ед). Нижний слот занимает картридж с красителями. Объем внутреннего хранилища - два картриджа краски (100 000 ед). По команде от компьютера, принтер берет немного печатной массы и краски и "распечатывает" в крайний правый слот запрограммированную модель. На модель из этого гайда, состоящую из 21 фигуры, принтер потратил 424 единицы массы и 314 единиц краски. 3. Отпечатанный блок Модель для печати задается в виде списка "фигур" - параллелепипедов. Каждая фигура отмечена координатами противоположных углов. Она имеет свою текстуру, цвет оттенка (если необходимо) а также состояние (true/false). Максимальное количество фигур в модели - 24, по умолчанию. Координаты блока тремя числами (X, Y, Z) в пределах от 0 до 16. Блок может переключать свое состояние, когда игрок кликает по нему правой кнопкой мыши, или на блок подается сигнал редстоуна. По умолчанию блок имеет форму, заданную блоками с состоянием false, и сменяет ее на форму из блоков с состоянием true, при активации. Кроме того блок имеет несколько дополнительных общих флагов, которые определяют его название, описание и некоторые другие параметры. 4. Программирование принтера Есть два способа распечатать свою модель. Через компонент принтера и прямое управление, либо при помощи стардартной программки print3d от Сангара. 4.1 Компонент принтера Подключение принтера ничем не отличается от подключения любого другого устройства: local com = require('component')local printer = com.printer3d Компонент предоставляет набор функций для управления: reset() - сброс настроек и остановка печати setLabel(value:string) - задаем название будущего блока getLabel():string - получаем текущее название setTooltip(value:string) - задаем описание блока getTooltip():string - получаем описание setRedstoneEmitter(value:boolean) - определяет, излучает ли блок сигнал редстоуна в активированном состоянии isRedstoneEmitter():boolean - возвращает true, если блок излучает сигнал в активном состоянии setButtonMode(value:boolean) - определяем поведение блока при активации. Если true, то блок автоматически возвращается в неактивное состояние через несколько секунд после активации (как кнопка) isButtonMode():boolean - возвращает true, если блок находится в режиме "кнопки" addShape(minX:number, minY:number, minZ:number, maxX:number, maxY:number, maxZ:number, texture:string[, state:boolean=false][,tint:number]) - добавляет новую "фигуру" к форме блока. Фигура задана координатами. texture - название текстуры, state - для какого состояния фигура предназначена, tint - цвет оттенка фигуры getShapeCount():number - возвращает количество фигур в модели getMaxShapeCount():number - возвращает максимально возможное количество фигур commit([count:number]) - посылает принтеру текущую конфигурацию и начинает печать (count - количество копий, если не задано - равно 1) status(): string, number or boolean - возвращает состояние принтера - "buzy" и процент готовности, или "idle" и готовность предмета (true/false). 4.2 Программа print3d Код программы не включен в мод по умолчанию, поэтому его надо скачать из интернета. Последнюю версию можно найти на ГитХабе автора: https://github.com/OpenPrograms/Sangar-Programs/blob/master/print3d.lua Либо скачать с Pastebin: http://pastebin.com/b5rD8KcY (поставьте интернет-плату, и наберите в консоли компьютера команду pastebin get b5rD8KcY print3d) Эта программа по сути, читает параметры модели из текстового файла и передает принтеру. Формат вызова программы: print3d FILE [count] Где FILE - название файла с моделью, а необязательный параметр count - количество копий модели. Модели имеют простой формат - все параметры записываются в таблицу, по аналогии с Луа. Вот образец файла с моделью. { -- Это - название модели. Т.е. название будущего блока, которое будет видно -- в инвентаре и подсказке Waila. Название по умолчанию - "3D Print" label = "Example Model", -- Это описание предмета, такое, как будет видно в инвентаре. Если не задано, -- предмет не будет иметь описания tooltip = "Это демонстрационная модель, показывающая все возможности", emitRedstone = false, --[[ Если этот параметр равен false, блок работает как дверь, сменяя свое состояние при сигнале редстоуна. Если параметр равен true, блок работает как кнопка или рычаг - излучая сигнал при смене состояния. При этом блок не реагирует на сторонний сигнал. По умолчанию параметр равен false. ]] buttonMode = false, --[[ Если этот параметр равен false, модель работает как дверь или рычаг - то есть остается в том состоянии, в которое установлен игроком. Если параметр равен true, модель автоматически возвращается в неактивное состояние через несколько секунд после активации. По умолчанию параметр равен false. ]] -- Это список фигур модели, которые определяют, как она выглядит. -- Модель должна содержать как минимум одну фигуру (параллелепипед) -- в неактивном состоянии. -- Фигуры не могут быть "плоскими" т.е. не иметь объема. -- Каждая фигура задана шестью числами: minX, minY, minZ, maxX, maxY, maxZ. -- (Координаты двух противоположных углов.) -- Если смотреть спереди, ось X направлена вправо, ось Y - вверх и ось Z - вглубь. -- Дополнительно, каждая фигура длолжна обладать текстурой. Для того чтобы -- определить название текстуры, вы можете воспользоваться Определителем Текстуры -- (Texture Picker), кликнув им по нужному блоку. -- -- Модель имеет два состояния - неактивное (false, состояние по-умолчанию) -- и активное (true, состояние после активации блока). shapes = { -- Фигура идет от точки <0, 0, 0> (левый нижний угол) до <8, 8, 8> (середина), -- и имеет текстуру блока лазурита. { 0, 0, 0, 8, 8, 8, texture = "lapis_block" }, -- Фигура идет из точки <8, 8, 8> (середина) в <16, 16, 16> (правый верхний угол), -- и закрашена текстурой дубовой листвы. Фигура принадлежит активному состоянию -- модели и имеет светло-зеленый оттенок. { 8, 8, 8, 16, 16, 16, texture = "leaves_oak", state = true, tint = 0x48B518 } }} Т.е. описание модели просто содержит перечень всех тех параметров, которые задаются при помощи компонента, и список фигур из которых модель состоит. Набор тестовых моделей для изучения, можно найти здесь: https://github.com/OpenPrograms/Sangar-Programs/tree/master/models 5. Проектирование модели Разобьем мысленно рисунок запланированной модели на параллелепипеды. Она будет представлять собой тонкую плитку посередине блока, наподобие стекла или решетки. Руководствуясь сеткой координат и образцом выше, составим описание модели для текстового файла: { label = "Плитка 'Морда крипера'", emitRedstone = true, buttonMode = false, tooltip = "Секретный рычаг в виде головы крипера" shapes={ {0,14,7, 16,16,9, texture="quartz_block_side", tint=0x8eb200}, {0,2,7, 2,14,9, texture="quartz_block_side", tint=0x8eb200}, {6,10,7, 10,14,9, texture="quartz_block_side", tint=0x8eb200}, {14,2,7, 16,14,9, texture="quartz_block_side", tint=0x8eb200}, {2,2,7, 4,10,9, texture="quartz_block_side", tint=0x8eb200}, {4,8,7, 6,10,9, texture="quartz_block_side", tint=0x8eb200}, {10,8,7, 12,10,9, texture="quartz_block_side", tint=0x8eb200}, {12,2,7, 14,10,9, texture="quartz_block_side", tint=0x8eb200}, {6,2,7, 10,4,9, texture="quartz_block_side", tint=0x8eb200}, {0,0,7, 16,2,9, texture="quartz_block_side", tint=0x8eb200}, {0,14,7, 16,16,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {0,2,7, 2,14,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {6,10,7, 10,14,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {14,2,7, 16,14,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {2,2,7, 4,10,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {4,8,7, 6,10,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {10,8,7, 12,10,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {12,2,7, 14,10,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {6,2,7, 10,4,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {0,0,7, 16,2,9, texture="quartz_block_side", tint=0x8eb200, state=true}, {2,2,8, 14,14,9, texture="quartz_block_side", tint=0xe0301e, state=true}}} Итак, наша плитка имеет двойной набор фигур - для двух состояний, окрашенных в текстуру кварца с зеленым оттенком. Кнопка будет работать как рычаг, испуская сигнал в активном состоянии. Откройте файл командой open creeper. Скопируйте код плитки выше и вставьте в файл кнопкой [insert]. Затем сохраните ([Ctrl]+) и покиньте редактор ([Ctrl]+[W]). 6. Печать Все готово, принтер заправлен, модель спроектирована. Отправляем ее на печать! print3d creeper 7. Итоги Enjoy!
  5. 11 баллов
    Немногие знают, как работают палитры в OpenComputers. Расскажу здесь, как избавиться от необходимости прописывать гектары цветов в палитре, покажу, как упаковываются цвета в OpenComputers и дам пару алгоритмов для работы с индексами. Сразу условимся, что индексы палитр у нас будут начинаться с нуля. На каждой из трёх уровней видеокарт и мониторов своя поддерживаемая палитра цветов. Будем двигаться снизу вверх. Первый уровень Палитра состоит из двух цветов: чёрного и заданного в конфиге (по умолчанию белого). При конвертации цвета в индекс палитры вернётся ближайший к данному цвет из палитры. Для определения разницы между цветами здесь и далее используется функция delta. Вот как она выглядит (вместе с функций extract, выделяющей из числа вида 0xABCDEF числа 0xAB, 0xCD, 0xEF): local function extract(color) color = color % 0x1000000 local r = math.floor(color / 0x10000) local g = math.floor((color - r * 0x10000) / 0x100) local b = color - r * 0x10000 - g * 0x100 return r, g, bendlocal function delta(color1, color2) local r1, g1, b1 = extract(color1) local r2, g2, b2 = extract(color2) local dr = r1 - r2 local dg = g1 - g2 local db = b1 - b2 return (0.2126 * dr^2 + 0.7152 * dg^2 + 0.0722 * db^2)end Теперь можно конвертировать цвет в индекс палитры. Суть такова: выбираем из двух цветов ближайший и возвращаем его. local palette = { 0x000000, CONFIG.monochromeColor}local function t1deflate(color) -- Сначала проверяем, совпадает ли данный цвет -- с каким-либо из палитры for idx, v in pairs(palette) do if v == color then return idx end end -- Составляем таблицу разниц между цветами local deltas = {} for idx, v in pairs(palette) do table.append(deltas, {idx, delta(v, color)}) end -- Сортируем по увеличению разницы table.sort(deltas, function(a, b) return a[2] < b[2] end) -- Первый элемент будет с наимешьней разницей, -- то есть искомый. Возвращаем индекс. return deltas[1][1] - 1end В случае с конвертацией из из индекса в цвет всё просто. local function t1inflate(index) return palette[index + 1]end Как и говорил. Второй уровень В палитре второго уровня имеется 16 закреплённых цветов: local palette = {0xFFFFFF, 0xFFCC33, 0xCC66CC, 0x6699FF, 0xFFFF33, 0x33CC33, 0xFF6699, 0x333333, 0xCCCCCC, 0x336699, 0x9933CC, 0x333399, 0x663300, 0x336600, 0xFF3333, 0x000000} В остальном конвертация из иднекса в цвет и из цвета в иднекс аналогична алгоритмам для первого уровня. Так как они были даны в общем виде, код для них тот же самый. local t2deflate = t1deflatelocal t2inflate = t1inflate Третий уровень Палитра третьего уровня содержит уже 256 цветов: первые 16 цветов изменяются, а остальные соответствуют цветам палитры RGB-6-8-5. Это означает, что можно смешивать 6 оттенков красного, 8 оттенков зелёного и 5 оттенков синего. В общем-то, довольно очевидна причина такого выбора: человеческий глаз лучше всего различает оттенки зелёного и хуже всего - оттенки синего. В любом случае, здесь алгоритмец будет посложнее. Сначала нужно сгенерировать палитру. Начнём с первых 16 цветов. Они не включаются в палитру RGB-6-8-5, поэтому их заполнять нужно отдельно. В OpenComputers по умолчанию они содержат оттенки серого. Так как чёрный и белый уже включены в основную, зафиксированную палитру, то заново их дублировать смысла нет. local palette = {}-- grayscalefor i = 1, 16, 1 do palette[i] = 0xFF * i / (16 + 1) * 0x10101end Таким образом в таблице получаются следующие оттенки серого: 0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78,0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2, 0xE1, 0xF0 Эти цвета мы записываем в индексы от 0 до 15. Теперь нужно сгенерировать остальные цвета - они не изменяются. Здесь будет посложнее. Посмотрим на картинку с палитрой: В OpenComputers левая верхняя ячейка палитры (0x000000) имеет индекс 16, а правая нижняя (0xFFFFFF) имеет индекс 255. Индексы распределяются слева направо, сверху вниз. То есть правая верхняя ячейка (0x00FFFF) имеет индекс 55, а вторая сверху и левая (0x330000) - это номер 56. Отсюда вытекает следующий алгоритм нахождения цвета: сначала найти индексы отдельно по R, G, B, затем для каждого из этих трёх индексов найти соответствующий ему оттенок цвета, а затем всё сложить. for idx = 16, 255, 1 do local i = idx - 16 local iB = i % 5 local iG = (i / 5) % 8 local iR = (i / 5 / 8) % 6 local r = math.floor(iR * 0xFF / (6 - 1) + 0.5) local g = math.floor(iG * 0xFF / (8 - 1) + 0.5) local b = math.floor(iB * 0xFF / (5 - 1) + 0.5) palette[idx + 1] = r * 0x10000 + g * 0x100 + bend К слову сказать, math.floor(x + 0.5) - это округление до ближайшего целого. Всё. Палитра есть, теперь можно, наконец-то, конвертировать индексы между цветами. Из индексов получить цвет довольно просто. Достаточно использовать ту же функцию, что и для предыдущих уровней: t3inflate = t2inflate С обратной же конвертацией всё в разы сложнее. Функция, используемая в OC, подбирает ближайший цвет очень хитрым алгоритмом, который я привожу ниже. local function t3deflate(color) local paletteIndex = t2deflate(color) -- Если цвет из палитры, то используем значение выше for k, v in pairs(palette) do if v == color then return paletteIndex end end -- Иначе используем хитромудрый код local r, g, b = extract(color) local idxR = math.floor(r * (6 - 1) / 0xFF + 0.5) local idxG = math.floor(g * (8 - 1) / 0xFF + 0.5) local idxB = math.floor(b * (5 - 1) / 0xFF + 0.5) local deflated = 16 + idxR * 8 * 5 + idxG * 5 + idxB if (delta(t3inflate(deflated % 0x100), color) < delta(t3inflate(paletteIndex & 0x100), color)) then return deflated else return paletteIndex endend В общем-то, это всё. Показал портированный со Scala на Lua код, который используется в OpenComputers. С помощью этого можно оптимизировать операции с экраном, выбирая поддерживаемые монитором цвета. И заодно избавиться от таблиц цветов, которые некоторые буквально берут и копипастят в файл, даже не задумываясь об изменяемых цветах палитры. Особенно это важно, когда берётся значение цвета через gpu.get, потому что следующий код всегда вернёт false: local gpu = require("component").gpugpu.setForeground(0x20AFFF)gpu.setBackground(0x20AFFF)gpu.set(1, 1, "HI")return select(2, gpu.get(1, 1)) == 0x20AFFF И всё потому, что gpu.get возвращает уже приведённый к индексу из палитры цвет. А 0x20AFFF в палитре, если не менять первые 16 цветов, не имеется. Enjoy :P
  6. 11 баллов
    На днях я рассказывал об интересном языке для OpenComputers (и не только). MoonScript Но одно дело - прочитать об языке где-то. А совсем другое - попробовать язык самому. Именно этим я и предлагаю заняться. Для разогрева, начнем с чего-нибудь несложного. Например "Угадай число". Думаю все знают эту игру. Компьютер загадывает число, мы пытаемся угадать. На каждую нашу попытку, компьютер злорадно сообщает - "больше!", "меньше!" или "у вас закончились попытки!" и "вы проиграли!". Немного модифицируем исходную идею, и перенесем ее на 2d поле. Просто, чтобы не было скучно. ТЗ Что нам потребуется? 1) Отрисовать сетку Тут мы просто возьмем текущий размер дисплея, и разметим его на клеточки. 2) Загадать число 3) Слушать команды пользователя Юзер будет тыкать на клеточки. Нам надо будет слушать эвент touch. 4) Обновлять игровое поле в ответ Собственно после тыка, будем открывать клетку. Если это не та клетка - рисовать на ней стрелочку. Если та - рисовать победный баннер. Если закончились ходы - рисовать что-нибудь обидное. За дело Первым делом надо подключить все, что мы будем использовать. В Lua обычно мы при помощи команды require пишем все в локальные переменные. В MoonScript все переменные по дефолту локальны. Поэтому использовать ключевое слово local нет необходимости. Для подключения же, используется ключевое слово import: import getResolution setForeground setBackground set fill from require('component').gpuimport pull from require 'event'import ceil, random from mathimport rep from string Мы вытащили из нужных библиотек нужные функции. Ничего лишнего. Теперь объявим переменные, которые будут использоваться в коде. - Размеры экранаwidth, height = getResolution()width /= 2 -- потому что по горизонтали наши клетки займут 2 символаheight -= 1 -- потому что внизу будет статус-- Цветаwhite = 0xFFFFFFblack = 0x000000gray = 0x222222green = 0x00BB33yellow = 0xFFC04Cred = 0xFF0000pink = 0xFF0074violet = 0xD600FFblue = 0x4E5AFFcyan = 0x4ED7FFteal = 0x00CC99-- Заготовка для сетки - один ряд клетокgrid_line = rep("▒▒ ", ceil(width / 2))-- Наша цельtarget = { x: 0, y: 0 }-- Количество попытокmaxAttemts = ceil(width * height / 150) -- 150 - магический коэффициент сложности, больше - сложнее, меньше - легчеattempts = maxAttemts Тут тоже присутствует несколько новых фич MoonScript. Во-первых - это сдвоенные операции. Конструкции a /= b или a -= b означают тоже самое, что a = a / b и a = a - b. Во-вторых это новый синтаксис создания таблиц. Названия полей и их значения отделены двоеточиями. (Такое обозначение будет знакомо тем, кто владеет JavaScript). Для реализации геймплея и отрисовки всякой всячины, потребуется определить несколько функций. Тут мы столкнемся еще с несколькими новшествами, по сравнению с Луа. Первое, в MoonScript нету ключевого слова end. Блоки кода обозначаются отступом разной величины. Так что вам придется тщательно следить за тем, на каком уровне вы пишете команды. (Это чертовски полезно, и вырабатывает красивый стиль написания кода =), а не эти кошмарные простыни, где нельзя разобрать начал и хвостов.) Второе, функции объявляются конструкцией вида (a, b, c) -> .... Тут слева - набор аргументов, потом стрелочка - разделитель и блок кода, который собственно является телом функции. -- Очищаем экранclear = () -> setForeground white setBackground black fill 1, 1, width * 2, height + 1, ' '-- Рисуем сеткуgrid = -> setForeground gray setBackground black for y = 1, height set (if y % 2 == 0 then 1 else 3), y, grid_line Пустой набор аргументов можно опустить, как в функции grid. Кроме того, как несложно заметить, MoonScript позволяет вызывать функции, не используя скобочки. Продолжим. -- Открываем одну клеткуsign = (x, y) -> if x == target.x and y == target.y then black, white, "[]" elseif x == target.x and y < target.y then white, green, "▼▼" -- по неведомой мне причине, стрелки вниз в новом шрифте ОС 1.6 нету =) elseif x == target.x and y > target.y then white, violet, "↑↑" elseif x < target.x and y < target.y then white, teal, "↘↘" elseif x < target.x and y == target.y then white, cyan, "→→" elseif x < target.x and y > target.y then white, blue, "↗↗" elseif x > target.x and y < target.y then white, yellow, "↙↙" elseif x > target.x and y == target.y then white, red, "←←" elseif x > target.x and y > target.y then white, pink, "↖↖"cell = (x, y) -> fore, back, text = sign x, y setForeground fore setBackground back set x * 2 - 1, y, text Здесь функция sign сконструирована так, чтобы отдавать три переменных разом. Следует заметить, что в MoonScript можно не пользоваться оператором return. Функция автоматически вернет значение последнего оператора в теле. Кроме функций, значения умеют возвращать и условия. Поэтому в данном случае, функция возвращает значение условия, а условие возвращает три значения из той ветки, которая выполнится. Функция cell просто берет эти значения и отрисовывает в нужном месте клетку. Далее. -- Рисуем статусstatus = (state) -> setForeground white setBackground black fill 1, height + 1, width * 2, height + 1, ' ' set 2, height + 1, "[Угадай, где клад!]" switch state when 'win' setForeground green set 24, height + 1, "Вы победили!" when 'lose' setForeground red set 24, height + 1, "Вы проиграли!" else set 24, height + 1, "Попыток осталось: #{attempts}" set width * 2 - 10, height + 1, "[R] [Q]" Здесь тоже используются две новые конструкции. Первая - это switch. Наверняка многие уже знакомы с ним. По сути, это просто удобный вариант длинных условий, со множеством elseif. Свитч получает значение, а потом сравнивает с ним все ветки when. Какая совпадет - та и выполнится. Вторая - это интерполяция строк. В строку в двойных кавычках можно встраивать значения перменных (или даже кусочки кода), используя диез и фигурные скобки, как в функции выше. Последние приготовления: -- Генерируем цельsetTarget = -> target = { x: random(1, width), y: random(1, height) }-- Инициализируем игруnewGame = -> attempts = maxAttemts setTarget! clear! grid! status! Функция newGame использует специальный синтаксис для вызова функции, которой не нужны аргументы. Вместо того, чтобы писать setTarget(), MoonScript советует использовать восклицательный знак. setTarget!. Это довольно весело смотрится в коде. =) Ну чтож, все готово. Давайте соберем все написанное, и запилим немного игровой логики! -- Поехали!newGame!while true -- Ждем события event, _, x, y = pull! -- Обрабатываем его switch event when 'touch' -- Если был клик -- Открываем клетку, если остались попытки if attempts > 0 x = ceil(x / 2) cell x, y attempts -= 1 -- Обновляем инфу if x == target.x and y == target.y attempts = 0 status('win') elseif attempts == 0 status('lose') else status! when 'key_down' switch x when 113 -- Q: выход из игры break when 114 -- R: перезапуск newGame!clear! Вуаля! Оно работает. И даже можно поиграть. И даже победить =) Круто, правда? Не надо делать такое выражение лица, я знаю что на самом деле, вы со мной согласны. =) А вы, да-да, вы! - на задних рядах, хватит кидаться тапками! Полный код игрушки доступен тут: http://pastebin.com/M0sxk1QH Enjoy!
  7. 10 баллов
    Я очень обожаю дронов из OC, довольно быстрые и манёвренные(и дешёвые!). Меня смущает насколько автофермы из разных модов дорогие, так что вот решение этой проблемы: https://pastebin.com/9TBqRHPw (Для ленивых и счастливых обладателей интернет-карты: pastebin get 9TBqRHPw dronefarm.lua) (Проверьте, работает ли у вас сбор культуры на ПКМ, иначе же работать не будет(Версия на ЛКМ была, но она неудобная)) В программе всего 4 настройки: Размер фермы по X и Z Ожидание в секундах(Это нужно для того, чтобы культура успела вырасти) Ожидание при зарядке(Если дрон разрядился во время полёта) Процент заряда, при котором дрон вернётся домой Конфигурация дрона совсем простая, нужен лишь инвентарь(Можно и два инвентаря, так будет лучше). Установка довольно простая: Скачиваем ферму Делаем чистый EEPROM Вставляем в комплюхтер Пишем flash -q dronefarm.lua dronefarm(Не обязательно dronefarm, можно что угодно написать) Вставляем в дрона ??? Профит! Расстановка фермы: Где жёлтый - граница фермы Красный - место стоянки Длина и ширина может быть любой, главное чтобы зарядки хватило(Если у дрона переполнится инвентарь или разрядится до 20% от общей зарядки единиц - он вернётся на базу)
  8. 10 баллов
    Показывает основную информацию о системе и дисках, позволяет выбирать приоритетный и конкретные диски для загрузки. Из работающего: Информация о системе Краткая информация о дисках Загрузка через init.lua в корне диска Установка приоритетного загрузочного диска (при старте биос будет пытаться загрузится именно с него, а потом уже проверять другие диски) Выжигающий глаза интерфейс и код Форматирование дисков Загрузка в MineOS Из не работающего: Загрузка в Plan9k и SecureOS Вкладка настроек Частично работающее: Загрузка в MineOS (не будет работать если установлено значение приоритетного диска) Предстоит реализовать: Вкладку настроек с языком Включение/выключение авторана Функцию ремонта файла запуска системы (перекачка с репозиции) Модификатор запускаторов MineOS и OpenLoader Запуск файлов на уровне биоса Поддержку (хоть какую нибудь) дисков в блочном режиме Вырезать главный кусочек и сделать возможность работы без интернет карты Перелопатить интерфейс и код, дабы делать всё через ООП Для установки прошейте биос этим файлом: https://raw.githubusercontent.com/titan123023/OCBios/master/bios-starter.lua Сслыль на репозицию: https://github.com/titan123023/OCBios Для работы требуется: Интернет карта Монитор любого уровня Клавиатура (если хотите зайти в сам биос) Как минимум 1 палец (см описание выше)
  9. 10 баллов
    ПОЛНЫЙ ОБЗОР Computronics версии 1.5.5 Часть вторая: стандартные блоки. И снова я приветствую Вас, уважаемый читатель этого блога! Вашему вниманию представляю вторую часть полного обзора CX версии 1.5.5, в которой я поведаю Вам о: Cipher Block (шифратор) Advanced Cipher Block (продвинутый шифратор) Colorful Lamp (разноцветная лампочка) Tape Drive + Cassette tapes (кассетный привод и, собственно, кассеты)) I. Cipher Block a.k.a. "Шифратор" Алгоритмов шифрования уже и так огороды, но суровые разрабы CX не сдаются) На самом деле, может быть очень полезным блоком для каких-нибудь там ивентов. Почему? Этот блок позволяет шифровать и дешифровать определённую строку, используя в качестве ключа... не что иное, как... предметы! Да, знаю, поворот весьма и весьма неожиданный, но так оно и есть на самом деле. Функции. cipher.decrypt(encrypted_string:String):String — пытается расшифровать строку, используя как "ключ" предметы в инвентаре шифратора. В случае неудачи (неправильный код) выдаёт ошибку. cipher.encrypt(string_to_encrypt:String):String — шифрует данную строку, используя как "ключ" предметы в инвентаре шифратора. Возвращает зашифрованную строку. cipher.setLocked(lock:Boolean) — блокирует/открывает доступ к инвентарю шифратора. При попытке открыть заблокированный шифратор, игроку выдаётся предупреждение в чат. cipher.isLocked():Boolean — возвращает состояние блокировки шифратора на данный момент. Скриншоты: II. Advanced Cipher Block. a.k.a. "Продвинутый шифратор" Этот вариант шифратора отличается от предыдущего тем, что здесь нет необходимости задать предметы как ключ — для шифровки/расшифровки используется алгоритм RSA. Функции. adv_cipher.createKeySet(prime1:Number, prime2:Number):Keygen — создаёт и запускает процесс генерации пары ключей на основе двух простых чисел. Возвращается структура, содержашая данные методы: key_set.finished():Boolean — так как процесс генерации ключей не мгновенный, использовать ключи сразу же после создания генератора нельзя. Данная функция возвращает готовность ключей: true при завершённом процессе генерации и false, если процесс генерации не завершён. key_set.getKeys():Table, Table — данная функция возвращает пару сгенерированных ключей или nil при незавершённом процессе генерации. [*]adv_cipher.createRandomKeySet():Keygen — идентичен полностью прошлой функции за исключением того, что числа простые указывать не нужно — они выберутся случайно. [*]adv_cipher.decrypt(encrypted_string:String, private_key:Table):String — дешифрует данную строку, используя приватный ключ RSA. [*]adv_cipher.encrypt(string_to_encrypt:String, public_key:Table):String — шифрует данную строку, используя публичный ключ RSA. III. Colorful Lamp. a.k.a "Разноцветная лампочка" Блок, испускающий свет, цвет которого можно менять программно (всего цветов 32768, включая чёрный). Функции. lamp.getLampColor():Number — возвращает текущий цвет лампочки. lamp.setLampColor(color:Number):Boolean — устанавливает текущий цвет лампочки. Если цвет равен нулю, то лампочка выключается. Скриншоты: IV. Кассеты и всё, что с ними связано. IV.1. Cassette Tapes. a.k.a. "Кассеты" Кассеты — мощное переносное хранилище информации, как текстовой, так и музыкальной. Всего видов кассет в CX — ни много, ни мало — 8 штук! И каждый тип различается требованиями по ресурсам и вместительностью музыки в минутах. Деревянная — 2 минуты Железная — 4 минуты Стальная — 6 минут Золотая дешёвая — 8 минут Золотая дорогая — 16 минут Алмазная — 32 минуты "Дешёвая" незерстарровская — 64 минуты И, наконец, самая ненажная и дорогущая одновременно вещь, которая когда-либо существовала в Майначе... Дорогущая незерстарровская — 128 минут. Это больше, чем на CD-диске!)) Но и качество хромает. Тем не менее, на такую кассету можно записать больше данных, чем на РЭЙД с 3 алмазными дисками) IV.2. Tape Drive. a.k.a. "Стример" Но одной кассетой Вы удолевтвориться не сможете... Для считывания и записывания информации необходим аналог CD-ROM'а, но для кассет — кассетный проигрыватель, называемый стримером. Функции. tape.stop():Boolean — останавливает проигрывание кассеты. tape.setSpeed(speed:Number):Boolean — устанавливает скорость воспроизведения (от 0.25 до 2). tape.getLabel():String — возвращает метку касссеты. Если не задано, равно "". tape.setLabel(label:String):String — устанавливает метку кассеты. Она видна в тултипе кассеты и в кассетном приводе, если там вставлена дискета. Возвращается новая установленная метка кассеты. tape.getState():String — возвращает текущий статус кассетного привода: "RUNNING", если проигрывается кассета, или "STOPPED", если нет дискеты, или воспроизведение было остановлено. tape.seek(amount:Number) — перематывает кассету на данное количество байтов вперёд/назад (при отрицательном значении). tape.setVolume(volume:Number) — устанавливает громкость кассеты от 0 до 1 (принимаются дробные значения). tape.getSize():Number — возвращает размер музыкального содержимого кассеты в байтах. Полезно вместе с функцией tape.seek() для перемотки в начало. tape.play() — начинает проигрывание музыкального содержимого кассеты. tape.isEnd():Boolean — возвращает true, если проигрывание содержимого завершилось. Полезно для зацикливания музыки на дискете в совокупности с tape.getSize() и tape.seek(). tape.isReady():Boolean — возвращает true, если в приводе присутствует дискета. tape.read([length:Number]):Number|String — читает всё (или определённое кол-во байтов), что записано на кассету. tape.write(data:Number|String) — записывает на кассету данные. Программа. При вставке кассеты в привод, появляется программа tape, которая позволяет совершать базовые операции над кассетой без необходимости использовать интерпретатор Lua. Доступно следующее: tape play — начать проигрывание. tape pause — приостановить проигрывание. tape stop — остановить проигрывание и перемотать в начало. tape rewind — перемотать кассету в начало. tape label — получить метку кассеты. tape label label — установить метку label кассете в приводе. tape volume volume — установить громкость volume музыке на кассете. tape speed speed — установить скорость speed проигрывания. tape write path/to/audio/file — записать на кассету файл с жёсткого диска компьютера. tape write URL — записать на кассету музыку с удалённого сервера, доступную по адресу URL. Скриншоты: IV.3. Формат звуковых файлов DFPWM. Прочитав рассказ о воспроизведении звука, наверняка, Вы уже начали искать тот самый файл с вашей любимой музыкой. Но не всё так просто! Дело в том, что используется странный и непонятный формат файлов — DFPWM... Но где его искать? Шаг первый. Конвертер. Первым делом, придётся открыть http://www.google.com/ в отдельной вкладке, ведь мороки с музыкой будет много. Сначала найдите в интернете конвертеры из формата Вашего файла в формат WAV (можно пропустить, если изначально в WAV). Для Линукса это ffmpeg, например. Шаг второй. Получение файла DFPWM. У вас должен быть на руках WAV-файл с музыкой. На всякий случай попробуйте открыть его в аудиопроигрывателе, дабы убедиться в "правильности" файла. Если всё ОК — закрываем Гугл и идём дальше. Загрузите данный файл на свой компьютер: https://dl.dropboxusercontent.com/u/93572794/LionRay.jar Это конвертер из WAV в DFMPW. Выставьте права на исполнение, если они не соблюдены, и запустите файл через Java. Укажите расположение исходного WAV-файла и запустите процесс конвертации. Шаг третий. Сохранение файла. Если у Вас есть доступ к папке сохранения, то всё просто — откройте папку ~/saves/<имя_мира>/opencomputers/<адрес_диска>/ и переместите туда Ваш получившийся аудиофайл. Затем вставьте кассету в стример, подключите последний к компьютеру и пропишите tape write <имя_аудиофайла>. Иначе Вам придётся искать хостинг, выдающий прямые ссылки на файл. Загрузите файл и скопируйте ссылку. Затем вставьте интернет-карту в компьютер и пропишите следующее: tape write <ссылка_на_аудиофайл>. Дождитесь окончания загрузки. Фух, вот я, наконец, и закончил. В сумме на написание этого гайда ушло около шести часов ночного времени, так что думаю, что он Вам понравится) Оставляйте оценки, лайки, жду комментариев! А в следующей части я расскажу о четырёх новых картах, которые добавляет CX. Ссылка на страницу мода: http://wiki.vex.tty.sh/wiki:computronics
  10. 10 баллов
    0. Вступление Итак, представим себе, что вы, после бурного вечера с друзьями, идете к себе домой. Уже добрались почти до входных дверей - у тут на тебе! Компьютер который работает дверным замком, бессовестно взял отгул и отключился. Что делать? Как попасть домой? Как добраться до железного гада, чтобы объяснить всю глубину его заблуждений? К счастью, красная плата и сетевая карта имеют некоторые недокументированные на gamepedia (я забыл обновить статьи =)) возможности. Вы можете включить компьютер при помощи сигнала редстоуна, или кодового слова отправленного по сети. 1. Wake-On-Redstone component.redstone.setWakeThreshold(threshold:number):number Эта команда позволяет установить в компьютер "будильник", который сработает, если входящий сигнал редстоуна (поданный на корпус компьютера (если вы используете красную плату) или на блок красного контроллера) превысит порог значения threshold. И если компьютер был выключен - он включится. Т.е. для включения компьютера вы можете воспользоваться рычагом или нажимной пластиной. 2. Wake-On-LAN component.modem.setWakeMessage(message: string):string Если компьютер получит по сети (проводной или без), сообщение message, то он включится. При этом не имеет значения, по какому порту получено сообщение. Обе функции возвращают в качестве результата старое значение "будильника". Чтобы снять "будильник", установите значение 0 (для редстоуна) или nil (для модема). Ну, а для того, чтобы включенный компьютер тут же принялся за работу, пропишите нужные команды в файле autorun.lua в корне загрузочного диска.
  11. 10 баллов
    Перед тем, как я начну, хочу сразу обратиться к забугорным ребятам, читающим эту запись. Hey! If you are reading this, please tell Vexatos to document the sound card. The in-game manual page is a meaningless piece of text that explains nothing. Documentation is written to help others to get an idea of how something works. The sound card is a complex thing that definitely needs a how-to guide to be used in programs. So if he wants the sound card to be used in programs, he should write the proper documentation with the detailed description of each concept, feature, and component method. The following is the result of efforts put to understand how the sound card works. It took me several months until I realized how to make a simple beep. How am I supposed to create more complex waves? >_> Ну да ладно. Хей! Разбирался я недавно, как работает звуковая карта из CX, и поэтому хочу предоставить результаты своих трудов. Как и написано сверху, доков нет, автор мода бездействует, везде уныние и отчаяние, поэтому пришлось действовать по-хардкорному. То есть чтением исходников и научнейшим тыком. Итак, есть компьютер со звуковой картой. Нужен звук. Звучит просто, м? Звуковая карта даёт нам замечательные функции вроде установки ADSR-огибающей, типа волны, шума простого или из LFSR, амплитудной и частотной модуляции. Но мы тут решили заняться простым звуком, поэтому всякие LFSR, AM, FM безжалостно выкидываем. Получаем такой план: Открыть канал. Поставить тип волны. Задать частоту волны. Установить громкость. Обработать. 1. Открыть канал Э, извините, а что за каналы? ... В звуковой карте звук генерируется с помощью инструкций, которые выполняются друг за другом. Почти все работают с определённым каналом. Если бы канал был один, мы бы смогли играть в один момент времени только одну, условно, ноту. Чтобы параллельно шло сразу несколько звуковых волн, нужно использовать несколько каналов. На каждом можно задать свои тип и частоту волны, громкость, ADSR-огибающую. По умолчанию таких каналов в звуковой карте 8 штук. С каналами всё довольно просто: открытый канал генерирует звук, закрытый канал не генерирует звук (правда, нужно будет здесь кое-что поправить, когда будет изучать ADSR). Открыть канал можно с помощью функции sound.open(channel: number). Закрыть: sound.close(channel: number). 2. Поставить тип волны Всего типов звуковая карта поддерживает пять: шум (noise), меандр (square), синусоида (sine), треугольная (triangle) и пилообразная (sawtooth). Waveforms ru [CC BY-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0) или GFDL (http://www.gnu.org/copyleft/fdl.html)], автор Omegatron (original work) Kirill Borisenko (Russian translation; see File:Waveforms for Cyrillic Segment.png) Incnis Mrsi (ultimate work), с Викисклада Очевидно, что разные типы волн звучат по-разному. Установить тип волны можно с помощью функции sound.setWave(channel: number, type: number). Видно, что тип волны должен быть числом. Соответствующее типу волны число можно получить с помощью таблицы sound.modes. Например, sound.modes.sine или sound.modes.noise. 3. Задать частоту волны Чем больше частота, тем выше звук. Частота 440 Hz соответствует ноте ля в первой октаве. Другие частоты можно найти по табличке на Википедии. Используем функцию sound.setFrequency(channel: number, freq: number). 4. Установить громкость Громкость может быть в пределах от 0 до 1 включительно. Половина максимальной громкости - 0.5. И так далее. Функция: sound.setVolume(channel: number, volume: number). 5. Обработать Чтобы обработать все инструкции, нужно вызвать sound.process(). Но если вы просто возьмёте и вызовете функцию, то ничего не услышите. Дело в том, что, достигнув конца инструкций, звуковая карта прекращает генерировать звук. Поэтому нужно выставить некоторую задержку в конце всех других инструкций, чтобы звуковая карта подождала перед прекращением воспроизведения звука. Для этого служит sound.delay(delay: number). Задержка указывается в миллисекундах. Например, sound.delay(2500). При этом эта функция тоже является инструкцией, поэтому её можно выставить несколько раз. Однако если задержка превышает 5000 (5 секунд), то звуковая карта выдаст ошибку. Проиграв несколько типов волн, мы всё равно останемся неудовлетворёнными. Ну где это видано, что звук мгновенно нарастает и затухает? Чтобы как-то это контроллировать, мы воспользуемся ADSR-огибающей. На Википедии довольно хорошо написано, в чём смысл этого. Скопируем сюда оттуда пикчу: И вкратце распишем суть. Если вы хоть когда-либо слышали музыкальные инструменты, вы могли заметить, что громкость звука со временем меняется. У гитары громкость мгновенно нарастает и постепенно затухает, а у флейты нарастает не сразу, например. Чтобы очень-очень грубо моделировать эти инструменты, мы используем ADSR. Attack - это время нарастания громкости звука до максимальной (последняя устанавливается через sound.volume). Decay - время затухания сигнала сразу после достижения максимальной отметки до следующего параметра. Sustain - отметка громкости, к которой стремится Decay. Значение 1 - это максимальная громкость звука на канале (установленная с помощью sound.setVolume), 0 - отсутствие звука вовсе. При достижении отметки Sustain звук остаётся на этом уровне до "отпускания клавиши" (т.е. закрытия канала). Release - время затухания сигнала после закрытия канала, от отметки Sustain до нуля. Время везде в миллисекундах. Попробуем? Вызываем функцию sound.setADSR(channel: number, attack: number, decay: number, sustain: number, release: number) до пятого шага. Например sound.setADSR(1, 1000, 500, 0.33, 1000). И замечаем, что громкость меняется со временем. Yay! На этом счастливом моменте повествование обрывается. Итоговый код, который можно запустить и послушать примитивный бип: local sound = require("component").soundsound.close(1)sound.close(2)sound.open(1)sound.setWave(1, sound.modes.sine)sound.setFrequency(1, 440)sound.setVolume(1, 1)sound.setADSR(1, 1000, 500, 0.33, 1000)sound.delay(1000)sound.open(2)sound.setWave(2, sound.modes.noise)sound.setFrequency(2, 440)sound.setVolume(2, 0.6)sound.setADSR(2, 1, 250, 0, 1)sound.delay(1500)sound.process() К остальному, надеюсь, я ещё вернусь в другой записи. Сначала нужно самому понять, как оно работает в версии для CX. Поэтому наслаждаться пока приходится только бибикалкой.
  12. 10 баллов
    ПОЛНЫЙ ОБЗОР Computronics версии 1.5.5. Часть первая: стандартные блоки. Приветствую Вас, уважаемый читатель! В данном обзоре я попытаюсь рассказать о всём, что только есть в Computronics. И начать предлагаю со "стандартных" блоков. Итак, гостями сегодняшней части будут: Iron Note Block (железный нотный блок) Camera (камера) Radar (радар) Chatbox (чат-бокс) I: Iron Note Block. Железный нотный блок — аналог обычного нотного блока, управляемый исключительно компьютером и позволяющий указывать номер ноты (от нуля до 24) и инструмент. Последний указывается числом от нуля до шести: 0 — пианино; 1 — большой барабан; 2 — клики/палочки; 3 — малый барабан; 4 — бас-гитара; 5 — пианино; 6 — бас-гитара. Функции: iron_noteblock.playSound(instrument, note) — проигрывает ноту с номером note на инструменте instrument (кроме номера инструмента, можно написать название) Блок: II: Camera. Камера — блок, позволяющий Вам получать дистанцию до ближайшего блока. При этом, можно установить угол "поворота" камеры по обеим плоскостям (X и Y). Максимальное значение "поворота" равно единице, минимальное — -1. Функции : camera.distance([x, y]) — получить дистанцию до ближайшего блока с определённым углом "поворота". Если опущено, то равно 0, 0. Блок: III: Radar. Радар позволяет получать информацию об игроках, мобах, предметах на земле и энтитей в определённом радиусе, но не дальше указанного в файле конфигурации мода предела. Все координаты относительные! Функции: radar.getEntities([range]) — возвращает информацию обо всех сущностях. Структура возвращаемой таблицы у этой и последующих двух функций такова: radar.getPlayers([range]) — возвращает информацию об окружающих игроках radar.getMobs([range]) — возвращает информацию о мобах поблизости radar.getItems([range]) — возвращает таблицу с предметами на земле около радара. Структура данной таблицы: Блок: IV: Chatbox. Последний в данной части блок — чат-бокс. Этот компонент позволяет отправлять и принимать сообщения в/из игрового чат (-а) в определённом радиусе. Функции: chatbox.getDistance() — возвращает текущий установленный радиус действия чат-бокса. chatbox.getName() — возвращает текущее установленное "имя" чат-бокса. chatbox.say(msg[, range]) — отправляет сообщение msg в чат в радиусе range. Если не указано, равно установленному. Возвращает true при успехе. chatbox.setDistance(range) — устанавливает радиус действия чат-бокса. Возвращает новый радиус. chatbox.setName(name) — устанавливает "имя" чат-бокса. Возвращает новое "имя". События: chat_message(UUID, sender, msg) — генерируется при отправке сообщения msg в чат игроком sender с UUID UUID. Скриншоты: Вот мы и подошли к концу данной части. В следующей части я расскажу о Chiper Block, Advanced Chiper Block, Colorful Lamp и Tape Drive. А пока — жду комментариев, оценок Ссылка на страницу мода: http://wiki.vex.tty.sh/wiki:computronics << НАЗАД в башню Fingercomp
  13. 10 баллов
    Прогулка с экскурсоводом по обновлённой части парка "OpenComputers". Глянем на новые вещи и попытаемся разобраться. Начнём с самого значительного изменения. Серверные Стойки. Ну тут всё интересно. Пугающая штука теперь — интерфейс стойки. А на хотбаре у меня лежат орудия пыток. Думаю, предпоследний предмет опознали — это сервер T3. По нажатию ПКМ этим предметом всё так же открывается интерфейс подобный компьютерному, куда можно вставить компоненты. Заменил я его на креативный, так как я играю в креативе, но уровень не так важен. Кладём три предпоследних предмета в стойку. Видим эту страшную картину. Но у нас же вроде гайд, поэтому добавим стрелочек. (2) — это сервер креативного уровня. В нём стандартный набор компонентов + инет- и беспроводная сетевая карты. (1) — это Server Terminal. Об его функции я расскажу позже. (3) — специальный дисководик для серверов. Вместо отдельного чукчёмного блока. Функции абсолютно те же. Сразу скажу, что (6) — это та же кнопка, что и [internal/External] в прошлых версиях, а так как её практическое использование нулевое, я промолчу про её функцию. Справа от слотов для серверов и модулей есть 6 линий разноцветных (7). Под каждой линией есть изображение стороны игральной кости (4), символически обозначающее эту линию. Их расшифровка — (5). Получается, для каждой из пяти сторон стойки (передняя не считается) в интерфейсе отдельная линия. Напротив слотов с предметами на линиях образуются точки (9), (10), .... Они требуются для соединения компонентов для серверов . То есть, подключив сервер (2) и компоненты к нижней стороне в интерфейсе, кликнув по большим точкам на линиях, для сервера (2) становятся доступны Server Terminal (1), Rack Disk Drive (3) и компоненты с нижней стороны. Неожиданно просто. А что же за маленькая точечка (8) напротив сервера? Оказывается, она служит для подключения сетевой карты в сервере к какой-либо стороне. Действует так же, как и в прошлых версиях. Теперь про (1), как и обещал. Если раньше всё было очень просто — берём Remote Terminal, подключаем и просто работаем, то теперь всё плохо. Эта штука позволяет подключённому к этой же стороне сервер у работать с удалёнными терминалами. Для этого берём Remote Terminal и делаем им ПКМ по компоненту в серверной стойке. Думаю, опознаете. Если загорится лампочка на компоненте в стойке — всё ОК. Если же тратить ресурсы на эту штуку не хочется, достаточно просто от указанной стороны компонентов провести кабель к монитору и клавиатуре. "Эм, а как включить сервер?" Теперь всё управление ими ведётся через ПКМ по серверу в стойке. Щёлкаем и можем включить сервер, потушить его и даже сменить компоненты во время работы! Кстати, о дисководах. В него и в дисковод обычный можно вставлять и изымать дискеты через Шифт-ПКМ. Очень удобно. Теперь сходим к роботу, так как в OpenComputers появился новый апгрейд: торговый. Торговый апгрейд для робота — апгрейд второго уровня, при подключении предоставляет компонент "trading" . У него всего одна функция — trading.getTrades() , возвращающая таблицу предложений жителей в радиусе 8 блоков от робота. Каждый элемент представляет собою одну сделку одного из жителей. Структура: {getInput = function():table, table, getOutput = function():table, isEnabled = function():boolean, trade = function():boolean[, string]} Функция getInput() возвращает таблицы с описанием необходимых предметов. По сути, это то же описание, что возвращает контроллер инвентаря — метаданные, имеет ли нбт-теги, имя предмета, его айдишник, максимальное повреждение, размер стэка и количество предметов, необходимых для торговли. Если второй предмет не требуется для торговли — вторая таблица будет равняться nil . Функция getOutput() действует по схожему с предыдущим принципу, только возвращает таблицу с описанием выходного предмета. Функция isEnabled() возвращает, интересна ли эта сделка на текущий момент жителю. Как известно, после 7 сделок она блокируется. Для разблокирования надо совершить другую сделку с этим же торговцем. Функция trade() , наконец, совершает сделку. Её условия: в инвентаре робота должно быть достаточное количество предметов для сделки, а предложение должно быть активно. Если всё верно, предметы обмениваются в инвентарь робота. Ошибки: false, "not enough items to trade" — в инвентаре робота недостаточно предметов для торговли. false, "trade is disabled" — житель более не заинтересован в этом предложении (было совершено 7 сделок). Кроме того, ещё одно мелкое изменение — для дисковода появился собственный компонент "disk_drive". Он есть только у Rack Disk Drive и Disk Drive, но не во встроенных в компьютер. Функция isEmpty() возвратит статус дисковода — есть ли в нём диск. Функция eject([velocity]) выплюнет диск из дисковода. Если дать как аргумент число (числа более 1 смысла не имеют, так как эффект тот же), диску передастся определённая скорость. Вот пример для максимальной скорости: Ещё из изменений — интернет-карта. Функция request() принимает третьим опциональным аргументом таблицу хедеров. Например, {["Accept-Encoding"] = "application/json"} . Это очень крутое изменение — так, для работы с чатом форума с OpenComputers теперь нет никаких технических преград. А ещё можно наконец-то запилить логин на сайты... Ах, применений много. Для модняков. Если дронотапки совместить с красителями, как кожанку, то неон на них покрасится. Для смытия краски достаточно кинуть тапки в ванильный котёл с водой, как кожаную броню. Если у меня хватит духу написать вторую часть, то, скорее всего, я начну рассказывать об изменениях в OpenOS 1.6. Ибо материала там тонны. Пока что не забудьте проголосовать в опросике сверху. Порадуйте диванных аналитиков.
  14. 10 баллов
    Здравствуй, брат автоматизатор. Надеюсь, ты помнишь, что всеми нами любимый брат qwertyMAN порадовал нас своей охранной системой турелей. И казалось бы, всё замечательно: турельки бьют прицельно, гриферы боятся, а мобы рассыпаются в лут. Но как всегда я нашел, к чему придраться. Не смотря на прицельный огонь, направление турели на цель вычисляется по очень неэффективному алгоритму. Весь код охранной системы я разбирать не буду, сосредоточусь только на математике. Остаток от деления Начнем с такого фрагмента: local function kostil(x) while true do if x>=360 then x = x - 360 elseif x<0 then x = x + 360 else break end end return xend По названию функции видно, что автор осознавал ущербность этого кода, но лучшего решения не знал или забыл. Разберемся, что делает этот код. В цикле вычитает 360 из аргумента, если он больше или равен 360, или добавляет 360, если меньше нуля. А по сути, приводит значение угла к диапазону [0,360). Зачем это делается? Ведь, например, углы и -90˚ и 270˚ указывают одинаковое направление. Сколько бы полных оборотов (360˚) в какую бы сторону мы не совершили, направление от этого не изменится. Тем не менее турель из OpenSecurity не принимает угол, выходящий за границы диапазона [0..360]. Приведение угла к нужному диапазону называют нормализацией. Угол можно нормализовать и в других диапазонах с полным углом, например [-180,+180]. Но наша турель требует диапазон [0,360]. Как же эффективно произвести нормализацию? Лучшим решением является операция взятия остатка от деления. Заглянем в справочник: a % b == a — math.floor(a/b)*b Не сложно увидеть, что a % b дает нам ровно тот же результат, что и костыль qwertyMAN'а, но код сильно сократился и стал выполняться быстрее. qwertyMAN с этого костыля быстро спрыгнул, и в следующей версии упростил свой код, но поверь мне, брат, на форуме есть много таких костылей, и калеки не спешат с них слезать. Вот, например, фрагмент кода, до которого я уже давно хотел докопаться. Код слишком длинный не только для своего функционала, но и для этой статьи, поэтому я спрячу его в спойлер: Можно ли этот код упростить? Легко. Для начала заменим строки числами, например, по такой схеме: N=0; W=1; S=2; E=3 После чего становится очевидным такое решение: function smartTurnLeft() robot.turnLeft(); N=(N+1)%4; endfunction smartTurnRight() robot.turnRight(); N=(N-1)%4; endfunction smartTurnAround() robot.turnAround(); N=(N+2)%4; end С какой стороны света начинать отсчет, и в каком направлении, это уже другой вопрос, но принцип остается неизменным. Главное, что код упростился, он не занимает огромное место в памяти и быстро выполняется. Конечно, при использовании некоторых приближенных к машинным языков и при определенных условиях работы алгоритма использование деления может оказаться менее эффективным, чем проверки условий с последующим сложением/вычитанием. Но интерпретируемые языки, к которым относится Lua, это преимущество нивелируют. Поэтому по возможности используй операцию взятия остатка от деления при обсчете всяких циклических значений. Это удобно и эффективно. Тригонометрия Теперь взгляни на эту функцию local function pointer(x,y,z) local distXY = math.sqrt(x^2+z^2) local distDY = math.sqrt(y^2+distXY^2) local outX = math.deg(math.acos(x/distXY))+90 local outY = 90-math.deg(math.acos(y/distDY)) if z<0 then outX = kostil(180-outX) end return outX,outYend Что она делает? Понять не сложно: вычисляет угловые координаты цели: азимут и угол места в градусах. Что тут не так? 1) присутствует acos с последующим добавлением/вычитанием 90˚, хотя известно, что и синус и косинус при добавлении/вычитании 90˚ преобразуются друг в друга. На этом я задерживаться не буду, формулы и их вывод есть в любом учебнике. 2) использование только asin или только acos тоже является не лучшей идеей: asin имеет низкое разрешение по углу в окрестности +/-90˚, а acos – в области 0 ˚и 180˚, снижая точность наведения, и для ее повышения потребуется использовать asin в окрестностях 0 ˚и 180˚ и acos в окрестности +/-90˚. 3) вычисление синусов и косинусов требует вычисления расстояния до цели r=sqrt(x*x+z*z), а, например, вычисление тангенса не требует. 4) область значений asin, acos и atan не покрывает полный оборот в 360˚, поэтому приходится прибегать к дополнительным вычислениям, как, например, это сделал автор: if z<0 then outX = (180-outX)%360 end. 5) не сошелся свет клином на всем известных со школы синусах, косинусах и тангенсах. Уделив несколько минут чтению списка математических функций, можно обнаружить такую красоту: В геометрии об этом не рассказывают, но такая функция имеется в стандартной библиотеке, пожалуй, любого высокоуровневого языка программирования. С ее помощью мы находим азимут цели единственной строкой azimuth=math.atan2(x, -z). Осталось только выполнить преобразование в градусы, да скорректировать возвращаемый диапазон углов c [-180,+180] на принимаемый турелью [0..360], с чем мы уже разобрались. Теперь надо правильно заполнить аргументы функции atan2. Для этого приведем всё, что у нас имеется, к картинке из школьного учебника. Во-первых, на картинках в школьном учебнике угол растет при повороте от оси X, к оси Y, и тангенс угла вычисляется как tg(α) = y/x. В справочнике же к atan2 указаны аргументы atan2(x, y) для вычисления арктангенса x/y. То есть, нам следует поменять аргументы местами. Имеем: math.atan2(y, x) Теперь разберемся с координатами мира Майнкрафта, положением турели, и тоже приведем их к картинке из школьного учебника. Сначала нарисуем координаты Майнкрафта при обращении лицом на север, вид сверху. Ось X направлена на восток, ось Z – на юг. Азимут поворота турели отсчитывается от северного направления по часовой стрелке. Прошу простить мне изображение угла прямой линией, а не дугой. Надеюсь, это не сильно помешает пониманию выполненных преобразований. X, Z – координаты мира Майнкрафта; R – вектор на цель; α – небольшой положительный угол между нулевым положением турели и вектором на цель. На первом рисунке изображены исходные координаты майна и поворота турели. На втором – поворот рисунка на 90˚ по часовой стрелке. На третьем – отражение рисунка по вертикали (как бы взгляд на плоскость карты не сверху, а снизу, из-под земли). В принципе, можно было бы обойтись без второго рисунка, отразив первый по диагонали, идущей из правого верхнего угла, но для улучшения восприятия я привел оба рисунка. На четвертом рисунке выполняется инверсия оси Z. Важно понять, что от всех этих преобразований координаты совершенно не меняются, меняется лишь их представление. И вообще следует помнить, что координаты не существуют в реальности и являются лишь математической абстракцией, которую легко можно вывернуть наизнанку в отличие от реальных объектов. Как ни вращай мир Майнкрафта на рисунках, он от этого не сдвинется и не изменится. Меняется лишь твоя точка зрения, но она-то и позволяет тебе упростить программу, избавившись от бесполезных вычислений. Все совершённые преобразования были нужны лишь для наглядности, и из них можно вывести более простое правило. Тригонометрия из школьного учебника основана на росте угла от оси X к оси Y. Но аналогичные формулы применимы при росте угла от оси -Z к оси X при соответствующих заменах в формулах. То есть, надо всего лишь знать от какой оси начинается рост угла и к какой оси происходит движение. В результате выполненных преобразований ты можешь легко заметить, что координаты из учебника (x,y) соответствуют координатам Майнкрафта (-z,x). В нашем случае: sin(α) = y/r → sin(α) = x/rcos(α) = x/r → cos(α) = -z/rtg(α) = y/x → tg(α) = x/-z Таким образом наш код приобретает вид: math.atan2(x, -z) Осталось лишь преобразовать радианы в градусы и нормализовать их в диапазоне [0..360]: azimuth=math.deg(math.atan2(x,-z))%360 Аналогичным образом вычисляется и угол места с той разницей, что ему не требуется нормализация. Вращать координаты тоже не надо. Но есть небольшой нюанс: угол места вычисляется относительно горизонтальной плоскости, для чего требуется найти расстояние до цели по горизонтали, и оно легко вычисляется по теореме Пифагора: Теперь тело функции, вычисляющей углы направления турели, умещается в три строки. local azimuth=math.deg(math.atan2(x,-z))%360local elevation=math.deg(math.atan2(y,math.sqrt(x*x+z*z)))return azimuth, elevation Или даже в одну, если не создавать промежуточные переменные и сразу возвращать результат. Вот так благодаря математике мы смогли сократить код программы на полтора десятка строк, а заодно и ускорили программу, избавившись от лишних вычислений. Кроме того сам код стал более понятным и наглядным. Не спеши кодить, подумай о математике, брат
  15. 9 баллов
    В звуковой карточке есть дохрена функционала - поэтому она и крутая. В этой части попытаюсь объяснить достаточно сложные штуки, которые используют большие дяди. Надеюсь, что вы прочитали и поняли две предыдущие части цикла - это будет довольно важно для последующего повествования. [Раньше тут был полноценный пост с эмбедом, но после переезда оно всё, соответственно, сломалось. Текст доступен здесь.]
  16. 9 баллов
    Потоки — очень полезные штуки, позволяющие исполнять несколько кусков кода. Раньше для их использования приходилось скачивать отдельную библиотеку, работающую через костыли. Начиная с OpenOS 1.6.4, они есть в стандартной поставке ОС — в модуле thread. Давайте посмотрим, из чего она состоит — и в чём её преимущество перед любыми другим библиотеками. Начнём с версий. OpenOS 1.6.4 — версия, включённая в OpenComputers 1.7.0. Если не хотите возиться с обновлением системы вручную, требуется иметь версию выше или равную 1.7.0. Сразу обращаю внимание на самую важную вещь: потоки не могут исполняться одновременно. В один момент времени только один поток может работать. В чём тогда красота тредов? Они автономны, то есть: Начинают исполнение сразу же после создания. Передают исполнение в другие потоки в местах, указанных использователем, — при том или ином вызове computer.pullSignal (os.sleep, event.pull и т. д.). Автоматически продолжают своё исполнение без необходимости самостоятельно их стартовать. Потоки можно убить и приостановить. Они неблокирующие: Вызов computer.pullSignal не блокирует исполнение других потоков. Они отцепляемые: Процесс, в котором был создан поток, называется родительским. При завершении родительского процесса все потоки останавливаются. Поток может отсоединиться от родительского процесса и работать полностью автономно — например, как слушатели событий. Поток может сменить родителя на другого. Поток сам является процессом и потому может создавать дочерние потоки. Работающий поток не даёт завершиться своему родителю. Они независимы при обработке событий: Потоки не наследуют и не передают дочерним свой набор слушателей событий. Все слушатели событий и таймеры принадлежат только конкретному потоку. Как следствие, поток не может изменять их набор в другом. Слушатели и таймеры автоматически удаляются при завершении потока, даже если завершение вызвано ошибкой. Приостановленные потоки игнорирует события. Если несколько потоков вызвали event.pull на одно и то же событие, они оба его получат. Этот набор фич в таком объёме присутствует только в этой библиотеке, и ни одна другая и не даёт столько простоты в работе с ними. Пожалуй, приступим к использованию. Потоки создаются функцией thread.create: первым аргументом передаётся функция, дальше идут аргументы к ней. local thread = require("thread")local t = thread.create(function(a, b) print("В потоке получены аргументы:", a, b)end, 21, 42) Функция возвращает объект потока. Его же может получить сам поток вызовом thread.current() — однако если вызвана не в потоке, то возвращает nil. На всякий случай, основной процесс не является потоком. Объект потока позволяет чудить различные вещи с потоком. t:suspend() приостанавливает поток. Как уже сказано, такой поток не будет получать события и обрабатывать тики таймера. Забавно, что если приостановить поток, когда он ждёт события, то неизвестно, что он получит после его возобновления. t:resume() возобновляет работу ранее приостановленного потока. Так как созданные потоки сразу начинают работу, то обычно этот метод вызывать не придётся. t:kill() убивает поток, то есть завершает его, удаляя всех слушателей и таймеры. Возобновить работу потока после того, как он убит, нельзя. t:status() возвращает строку со статусом потока: "running" — поток работает или блокирован другим. Такой поток не даёт завершиться своему родителю. "suspended" — поток приостановлен. Его дочерние потоки также будут приостановлены. Когда родительский процесс завершается, такой поток автоматически убивается. "dead" — поток мёртв. t:attach() позволяет сменить родителя у потока. Без аргумента поток будет присоединён к текущему процессу. Переданное как аргумент число позволяет указать, к кому присоединить: 0 — текущий процесс, 1 — родитель текущего и т. д. t:detach() отцепляет поток от родителя. Такой поток будет работать до его остановки или перезагрузки компьютера. t:join() останавливает процесс, в котором была вызвана это функция, до завершения потока t. local thread = require("thread")local t = thread.create(function() os.sleep(10)end)t:join() -- остановится на 10 секунд Можно передать первым аргументом этой функции число, которое будет служит таймаутом (в секундах). Тогда, если не успеет завершиться поток за это время, join завершится досрочно. t:join ждёт только одного потока. Для групп потоков есть функции thread.waitForAny и thread.waitForAll — обратите внимание, что это функции библиотеки, а не методы объекта потока. Обе функции первым аргументом требуют таблицу с потоками, а вторым опционально можно задать таймаут. thread.waitForAll ждёт, пока завершатся все потоки из списка. local thread = require("thread")local t1 = thread.create(function() os.sleep(10)end)local t2 = thread.create(function() os.sleep(15)end)thread.waitForAll({t1, t2})print("Это сообщение будет написано через 15 секунд") thread.waitForAny ждёт, пока завершится хотя бы один поток из списка. local thread = require("thread")local t1 = thread.create(function() os.sleep(10)end)local t2 = thread.create(function() os.sleep(15)end)thread.waitForAny({t1, t2})print("Это сообщение будет написано через 10 секунд") Что будет, если поток бросает ошибку? При ошибке в потоке она не будет проброшена в родительский процесс. Как и со слушателями, она будет записана в файл /tmp/event.log, но родитель не сможет узнать причину ошибки — и, вообще, успешно ли завершился поток. local thread = require("thread")local t = thread.create(function() os.sleep(3) error("test")end)print(t:status())--> runningt:join()print(t:status())--> dead Кроме того, событие жёстокого прерывания (Ctrl+Alt+C) не передаётся всем процессам — только одному; причём неизвестно, какому именно: родителю или одному из его потоков. Если вы используете потоки, первым делом сделайте один, который будет ждать события interrupted и подчищать ресурсы. local thread = require("thread")local cleanupThread = thread.create(function() event.pull("interrupted") print("Принял ^C, чищу всякие ресурсы")end)local mainThread = thread.create(function() while true do local input = io.read() if input == "exit" then break end endend)thread.waitForAny({cleanupThread, mainThread})os.exit(0) Обратите внимание, что в конце программы стоит os.exit. Где-то я уже упоминал не раз, что родительский процесс, достигнув конца программы, не завершится до тех пор, пока работает хотя бы один из его дочерних потоков. Вызов os.exit() позволяет выйти из программы, закрыв все дочерние потоки. Что, безусловно, достаточно удобно. Есть ещё один момент. Допустим, данная программа запускается в роботе: local robot = require("robot")local thread = require("thread")local moveThread = thread.create(function() while true do robot.forward() endend)local inputThread = thread.create(function() while true do local input = io.read() if input == "exit" then break end endend)thread.waitForAny({inputThread, moveThread})os.exit(0) Если вы запустите эту программу, то должны заметить, что вы ничего не сможете написать в роботе, хотя работает io.read. Дело в том, что функция robot.forward вызывает метод компонента, который блокирует исполнение компьютера. Пока робот двигается, на компьютере не может выполняться ни одна команда. Чтобы хоть что-то можно было вставить в строку, то поставьте после robot.forward какой-нибудь os.sleep(0) — он позволит соседнему потоку принять и обработать события. Тем не менее, строка ввода всё равно будет работать с тормозами. В подобном случае задумайтесь над тем, чтобы использовать вместо строки ввода иное средство коммуникации: редстоун, сеть, интернет-сокет. Несмотря на всё, библиотека действительно облегчает работу с потоками в OpenOS. Кроме того, очень удобно поместить все слушатели событий в один поток, чтобы они все автоматически были удалены после убийства потока. local event = require("event")local thread = require("thread")local mainThread = thread.create(function() event.listen("key_down", function(evt, addr, key, code, user) print("A key has been pressed!") end) while true do print("do something") os.sleep(0.5) endend)-- событие interrupted не ловится обработчикамиlocal intThread = thread.create(function() event.pull("interrupted")end)thread.waitForAny({mainThread, intThread})os.exit(0) Не нужно функции сохранять в переменные и помнить, что нужно ставить event.ignore в конце программы; не требуется ребутать компьютер, если программа завершилась с ошибкой, а до отключения слушателей дело не дошло. В общем, красота.
  17. 9 баллов
    Решил больше не ждать с этим. Где-то пару месяцев назад решил начать пилить одну штуку — кукбук, или книгу "рецептов". Изначально задумывалось как сборник просто именно рецептов как в кулинарной книге: тонна кода и немного объяснений; получилось наоборот, естественно, — до того, что в некоторых "рецептах" кода нет, — ну это, наверное, потому что я не умею толком через код объяснять. В любом случае, теперь это сборник полезных туториалов по практическому применению. Он разделён на 3 раздела. Lua — статьи, непосредственно затрагивающие код и написание программ. Сниппеты кода, гайды по функциям. OpenOS — статьи абстракции уровня выше немного. Здесь всё об использовании шелла, стандартных программ и прочих фичах дефолтной оси OC. OC — статьи, не относящиеся непосредственно к разработке программ или фичам OpenOS. Наверное, это in-world штуки всякие, по большей части. Например, инфа о том, как собрать идеальный хрякокоптер или правильно тестировать нанытов. Потом могут быть статьи о всяких блоках, да и прочих фичах самого мода. Когда я сейчас пишу эту запись, в кукбуке есть уже 13 рецептов. Ссылочка на книжку. Заходите, почитайте. Есть слухи, что на гитбуксе можно отсылать пулл реквесты... Они здесь называются чендж-реквестами, но разницы никакой. Если есть идея для ещё одного рецепта и желание написать статью — присывайте эти реквесты; если желания нет — можно написать идею в комментариях. Я пока не особо понимаю, чего ещё бы добавить в кукбук.
  18. 9 баллов
    Вкратце проедемся про изменениям с невероятно старой версии 1.5.5 до самой новой, 1.6.3. 1.5.6 / 2015-07-24 Большинство блоков из мода можно покрасить, тыкнув по ним красителем. Интеграция с модом Flamingo (самая нужная фича, конечно): через компы можно заставлять фламинго качаться. Интеграция с Armourer's Workshop. Улучшен улучшенный шифратор. Ключи быстрее генерируются. 1.5.7 / 2015-09-12 Разноцветный апгрейд добавлен, который делает роботов разноцветными. Можно вызвать component.colors.setColor(color: number) и покрасить корпус робота в желаемый цвет. Интересная штука. 1.5.8 / 2015-10-11 Эффект hive_mind для наномашинок. Часть интеграции с Forestry. Включив, можно тыкнуть пропитанной палкой из Forestry по желаемому улью с пчёлами - пчёлы станут летать над головой. Палкой же направлять можно пчёл на желаемую цель: пчёлы полетят к ней и станут жалить. Если отключить эффект, то пчёлы будут жалить игрока. 1.5.9 / 2015-10-22 Чатбоксики креативные стали писать во все измерения. 1.6.0 / 2015-11-28 Аудиокабели добавились. Их можно подключать к кассетным проигрывателям и к динамикам. Динамики будут воспроизводить звук вместо проигрывателя. Убрана поддержка NedoComputers, потому что этот мод сдох. Спустя год выпускается огромнейший апдейт мода, поэтому дальше расписываю фичи детальнее. 1.6.1 / 2016-11-12 Мод портирован на 1.8.9, 1.9.4 и 1.10. На новых версиях майна используется улучшенный кодек DFPWM1a. Старые записи будут очень тихими, поэтому их нужно переконвертировать с помощью LionRay. С новым кодеком гораздо меньше шума будет. Добавлена шумовая карта. Отключается от пищащей карты тем, что можно для каждого из 8 каналов задать тип волны: синусоида, меандр, треугольная и пилообразная. Допольнительно появляется буфер операций: можно добавить ноты и затем вызвать component.noise.process(), чтобы проиграть. Добавлена звуковая карта. Как работает этот монстр, я описывал в предыдущей записи. Потом опишу функции покруче, а пока можно побикать. Интеграция с TIS-3D, модом от Sangar. Это и новые модули: разноцветный, считыватель дискет, самовыпиливатель - и документация в мануале TIS-3D. Интеграция с OC 1.6. Добавлены дополнительные штуки для серверов. Плата с лампочками. Ключом можно менять конфигурацию, изменяя положение и количество лампочек. Как компонент предоставляет функции для включения/отключения лампочек и изменения цвета (True color). SSD. Расшифровывается как Server Self-Destructor. Очередная версия самой нужной вещи - самовыпиливателя, но для серверов. Если взорвать через функцию специальную, в серверной стойке пропадут все вещи. Серверный вариант батарейки, которую можно пихнуть в стойку. Можно ещё считывать количество энергии. Плата с переключателями. Можно тыкать по кнопочкам, включая или выключая их. А сервер потом может считывать положение переключателей. По просьбам трудящихся. [*]Добавлена функция getPosition() в проигрыватель, чтобы узнать текущую позицию на кассете. Именно: её несколько лет не было. Ну что поделать, бывает. [*]Стандартная программка для работы с проигрывателем tape починена для работы с HTTPS. Можно менять размер чанка и таймаут ожидания. И tape wipe добавилась для стирания всей инфы на кассете. [*]1.7.10 Цифровый сигнальный контроллер (интеграция с RailCraft). Надеюсь, когда-нибудь дойдут руки рассказать, как она работает. Но не тут. [*]1.7.10 Цифровый сигнальный приёмник (интеграция с RailCraft). [*]1.7.10 Рецепты для Gregtech 6. [*]1.8+ Больше не требуется устаналивать Asielib: либа встроена в мод. 1.6.2 / 2017-02-25 Фиксы, фиксы и ещё фиксы. Фиксы крашей, фикс тихих звуков в звуковых карточках, дискеты можно теперь получить, наконец, с помощью ключа. 1.6.3 / 2017-04-21 Добавлен синтезатор речи. Так как это охрененная штука, без пинка её так просто не завести. Чтобы она работала, нужно поставить сам синтезатор речи (MaryTTS с поддержкой Forge), файл голоса и файл языка. Женский голос и английский язык, например. К счастью, эти файлы нужны только на сервере. На клиент тянуть их не нужно. Работать так: speech_box.say(text: string) -- что-то сказать. speech_box.stop() -- остановить воспроизведение речи. speech_box.isProcessing():boolean -- проверить, воспроизводится ли сейчас речь. speech_box.setVolume(volume: number) -- установить громкость (от 0 до 1). Блоки теперь крафтятся не из земли и палок, наконец-то, а из чего-то повеселее. Используются предметы из OpenComputers. Динамики могут смотреть в любую из шести сторон. Директория для кассет перемещена в папку мира. При обновлении нужно перетащить её из папки кубача в папку мира, соответственно. Модуляция из-за глупой ошибки не работала вообще. Ну и ADSR не работал, если время Attack (нарастания) равно было нулю. Как-то так. За мною остаётся ещё долг в виде продолжения обзора этого интересного модика, но всё как-то лень. Пока можно спрашивать меня, как работают вещи из CX, читать страницы в мануале и документацию к методам. Для большинства вещей этого более чем достаточно. Have fun :P
  19. 9 баллов
    О 1.6 было говорено ещё с очень давних пор — примерно год назад. И наконец-то первая бета OC 1.6 доступна для скачивания. Вообще, 1.6 всё это время можно было загрузить как дев-версию — достаточно перейти на Jenkins. Однако билды там не всегда блещут стабильностью. Что изменилось: Полный ченджлог Sangar предоставит, когда отрелизится 1.6.0. Но благодаря ГитХабу я могу сравнить 1.5.22 и 1.6. Так что краткое переложение >150 коммитов: Новые серверные стойки. Модульность, крутой GUI и многое другое. Дисковод — компонент. Геолайзеру теперь можно задать не только колонну, но и прямоугольник. Терминальный сервер. Lua 5.3.2. В internet.request можно задавать хедеры. Ачивки теперь даются не только за крафт, но и за поднимание предметов. Торговый апгрейд для роботов. playSoundAt для дебаг-карт. __gc-метаметод оказался опасным — им можно перегрузить сервер. Теперь в настройках есть опция для включения этого метаметода. По умолчанию __gc отключён. OpenOS 1.6. Там мегатонны всяких изменений. И, кстати, эта система грузится на планке памяти первого уровня. Даже несмотря на новые проги, либы и пр. Дронотапки можно красить. Новый шрифт. Логирование чанклоадеров. Ну и множество других изменений. Качайте новую версию тут и крушите её. А обо всех найденных багах, как обычно, сообщать сюда.
  20. 9 баллов
    Как обрести счастье на IT-сервере “Не собирайте себе сокровищ на земле, где моль и ржа истребляют и где воры подкапывают и крадут, но собирайте себе сокровища на небе, где ни моль, ни ржа не истребляют и где воры не подкапываются и не крадут” (Матф.6:19-20). Часть первая. То измена, то засада. В последние два месяца я редко захожу в игру, в основном для проверки и поддержания привата. Даже форум редко просматриваю. Зайдя же в очередной раз на сервер после двухнедельного отсутствия в игре, я обнаружил себя на новом спавне, почти голым, в майке и трениках, без бура, джетпака и наношапочки. И самое печальное, без дома: /home не работал, и мой дом на карте тоже не просматривался. Да что об этом говорить – сама карта была совершенно новой. И я приуныл. И вот, стою я один, как Робинзон на острове, с комплектом железной брони и инструментов в инвентаре, но прямо сейчас я боюсь потерять даже их. Вокруг непроглядная ночь, наполненная голосами местной нечисти. А если очень сильно не повезет, можно даже погибнуть от лазера злодея на спавне. Стоящий на спавне сундочок Края кажется единственной надеждой спасти подаренное богами имущество. Но нет же, сундук не открывается, лишь выдается сообщение "У вас нет разрешение игрока прав администратора на использование предметов". Благо, форум подсказал мне про /enderchest. Я быстренько сложил свой примитивный скарб в виртуальный сундук, и стал неспешно оглядываться на спавне и ждать окончания ночи. И вот тут меня ждала вторая неожиданность – ночь не кончалась, время тянулось медленно, и это не фигура речи, это новая фишка сервера, как выяснилось. И я опять приуныл. Часть вторая. Спасение. Реально помогают лишь две вещи: голоса в ТОПах и программирование, как и заповедовал нам AlexCC, в этом он преуспел. Теоретически могли бы помочь друзья, но я не очень общительный человек, и в тот момент на сервере никого из игроков не было, да и друзья до сих пор сами буквально умирают от голода. На сервере находился только AlexCC, но я не стал тревожить его своим плачем. Даже Яхве не помогал евреям, пока те не вставали на путь исправления. За голоса я приобрел себе ПНВ, чтоб лучше видеть, наноботы, чтобы мягче падать, и несколько джетпаков, чтобы летать и не сильно заботиться об их зарядке, после чего, отбиваясь от зомбей и скелетов, стремительно закопался в гору недалеко от спавна и заприватил участок. Это сберегло мне время и душевное равновесие на старте игры. Потом я все же отклонился от праведной жизни, несколько раз сходив с киркой, а потом и буром в майн за рудами, построил батбокс для зарядки джетпака, а также всяческие дробилки-плавилки-сжималки-выжималки, скрафтил бур, пилу, и даже смог собрать свой первый компьютер, закупив для него лишь глину и кактусы. Сейчас же думаю, что на этом этапе я ошибался. Я не пробовал посчитать, но думаю, что стартовых денег достаточно для покупки ресурсов, необходимых для постройки первого хотя бы простого (или даже сложного) робота, способного к добыче ресурсов. Запрограммировать и отладить его можно в креативе, а можно просто взять одну из замечательных программ с форума computercraft.ru. А дальше лишь остается стоять рядом и, свернув окно майнкрафта, читать умные книжки, статьи и думать над следующими программами. И дом теперь тоже не хочется строить руками. Строительство должно быть автоматизировано. Всё. Всё в мире майнкрафта должно быть полностью и хорошенько томатизировано. Только в этом можно обрести счастье на IT-сервере. Смерти нет. Вайп не конец всему, если только всем для тебя не являлись сундуки, набитые рудой и выстроенный руками дворец. Твои программы и твои знания останутся с тобой и после вайпа, а робота даст администрация, насколько бы кровавой она ни была. Всё остальное должно прийти автоматически. В той горе, где я поселился, мне довелось узнать много всего интересного. Однажды, когда я жарил булыжник в электрической печке, не смотря на тщательно замурованные проходы, зашел ко мне человек в сияющем плаще. Ник его я не запомнил, хотя говорили мы с ним всю долгую ночь. Нет смысла пересказывать весь разговор, но запомнились некоторые его изречения: Блаженны нищие печками, ибо их есть царство IT. Блаженны ошибающиеся, ибо научатся. Блаженны спрашивающие, ибо они наследуют опыт IT. Блаженны алчущие и жаждущие знаний, ибо получат их. Блаженны помогающие, ибо они помощь получат. Блаженны думающие, ибо они программирование осилят. Блаженны программирующие, ибо они будут наречены сынами IT. Блаженны бегущие с серверов без OpenComputers, ибо их есть сервер IT. Блаженны вы, когда будут поносить вас и гнать и всячески неправедно злословить фанаты других серверов. Радуйтесь и веселитесь, ибо велика ваша награда на IT-сервере: так гнали и программистов, бывших прежде вас.
  21. 9 баллов
    Дамы и господа! Мы представляем Вам новый Девайс: Вэйпоинт!.. Собственно, вот. МАНУАЛ по вэйпоинту. Станьте Мастером по юзанью этой штуки за 5 шагов! I. Что это? Вэйпоинт — путевая точка — служит для указания роботу или дрону на конкретную локацию. Используется в совокупности с навигационным апгрейдом. Робот может получать относительные координаты места, силу подведённого к вэйпоинту редстоун-сигнала и название вэйпоинта. Внимание! Вэйпоинт указывает на блок, где спаунятся фиолетовые частицы!! II. Использование. Для сканирования местности и получения данных о вэйпоинтах, необходим навигационный апгрейд в роботе или в дроне. Тогда появляется новая функция: findWaypoints(range) :: table Возвращаемая таблица будет содержать следующие значения: { { label="Имя вэйпоинта", position={ 0, --| Относительные |- X 0, --| координаты |- Y 0, --| вэйпоинта. |- Z n=3 -- Значение данного параметра неизвестно. }, redstone=0 -- Сила редстоуна, подведённая к вэйпоинт-блоку. }, { label="Имя второго вэйпоинта", position={ 0, 0, 0, n=3 }, redstone=15 } ...} III. Подробности. Имя вэйпоинта устанавливается через GUI этого блока. Но есть и второй вариант: вэйпоинт регистрирует себя как компонент: Так что мы можем обратиться к его фукнкциям: getLabel() :: string -- возвращает текущее название вэйпоинтаsetLabel(label:string) -- устанавливает новое название вэйпоинта IV. Практика! Специально для теста я по-быстрому написал 2 простенькие программы: поиск вэйпоинтов и перемещение к данному вэйпоинту. Полигон для тестов выглядел так: С ред-сигналом был только вэйпоинт "Сундук с грязью", как подсказывает первая программа find: Теперь давайте использовать путевые точки по назначению! Куда более сырая вторая программа goto позволяет перемещаться на данный вэйпоинт. Так как дрон — слишком просто, будем использовать робота "Curiosity". После выполнения робот перемещается с грязевого сундука на высокий вэйпоинт: Из-за сырости программы возникают небольшие ошибочки Здесь робот хотел пройти сквозь компьютер и попасть к правому вэйпоинту на скрине, но у него это не получилось :| И последнее. Если робот не находит какой-то вэйпоинт (в данном случае — "набор слов"), он выдаёт ошибочку. V. Заключение. Вэйпоинты могут помочь роботу или дрону легче ориентироваться на местности. Ссылки на скачивание программ: find: wget http://www.pastebin.com/raw.php?i=s0KdZApY find.lua goto: wget http://www.pastebin.com/raw.php?i=nAqrJ9jT goto.lua [*]Жду комментариев, лайков и, может, даже оценок! Ведь теперь Вы можете с уверенностью использовать этот замечательный блок [*]И, внимание! Официальное видео от автора ОС, демонстрирующее интересное использование данного блока в повседневных целях.
  22. 8 баллов
    Представляю вам опять программу для робота, которая позволяет добывать руду, не лазая по пещерам. Робот, используя геолизер, может самостоятельно находить и добывать руду. Реализованы еще не все возможности, поэтому прошу тестировать и сообщать мне о багах. Требования: Корпус компьютера (уровень II или III) Апгрейд инвентарь (больше - лучше) Апгрейд контроллер инвентаря Жесткий диск EEPROM с прошитым Lua BIOS Геосканер Память (уровень I или выше) Процессор (любой) Апгрейд полета (I уровень) Алмазная кирка или аналогичный инструмент. Опционально: Апгрейд верстак Беспроводная сетевая карта Апгрейд батарея Апгрейд опыта Апгрейд чанклоадер Апгрейд генератор Апгрейд солнечная панель Эндерсундук из мода EnderStorage Установка: Скачать и сохранить файл как init.lua wget https://raw.githubusercontent.com/DOOBW/geominer/master/miner.lua init.lua Закинуть этот файл в корень диска. Добавить диск при сборке робота. Установить робота на платформу из твердых блоков. Дать роботу кирку. Поставить возле робота контейнер и зарядник. Нажать кнопку питания и наслаждаться процессом.
  23. 8 баллов
    Система предоставляет графическую оболочку для планшетов, имеющую минималистичный интерфейс и понятное только мне использование, а так же минимальное (надеюсь) потребление ОЗУ. Из фич оболочка дает: Возможность использования OpenOS частично без использования команд. Для особых случаев - используем контекстное меню -> "Выполнить команду" Возможность посылки уведомлений пользователю. Многозадачность не реализована, так что пассивную часть программы нужно активировать библиотекой thread из OpenOS Запуск программ-папок (*.pkg). Чисто для разграничения кода и возможности создания модулей Адаптивная отрисовка интерфейса. На экранах с разрешением по ширине, не кратной 20, могут возникать проблемы, однако без искусственного изменения разрешения такого не произойдет. Помощь в настройке при первом запуске. На случай проблем - на первом экране используется колёсико мыши. Блокировка экрана Горячие клавиши на главном экране (клик+delete - удалить, ctrl+e+клик - редактировать и подобное) QR-коды для быстрого доступа юзера к ссылкам В планах: Специальный фреймворк аля Zygote из андроида. Естественно абсолютно весь функционал переписывать не буду, однако основной останется. Этот фреймворк повлечет за собой полный рефакторинг кода (перевод системы на него), но полностью устранит все недостатки TabletOSNetwork - что бы было. Протокол сам в себе будет держать защиту от MITM (Сначала на DSA, потом переведу на ECDSA (реально сложно для меня пока)) и некоторую маршрутизацию с помощью специальных реле (что бы у юзеров планшеты не лагали). Установка - pastebin run 1xudmTa7 Выберите в установщике TabletOS и канал обновлений "Stable". В дальнейшем система будет уведомлять о обновлениях, при получении оного нужно будет зайти в настройки (контекстное меню в левом нижнем углу экрана) и там обновиться. В случае, когда при обновлении бросает ошибку - посмотрите изменения, там будут инструкции по ручному обновлению или переустановке системы. Если и это невозможно. переустановите систему. Данные должны сохраниться, а вот система - обновиться.
  24. 8 баллов
    Видел я на хабре пост четырёхлетней давности о включении лампы(в реальном мире) из майнкрафта. Вот он, если что: https://habr.com/ru/post/271527/ Тут я подумал - "А чем я собственно хуже? Почему нельзя контроллировать температуру реактора/дроноферму/дом датчиками движением?" Переходим к практике. Я имею вот такой дисплей купленный в поднебесной(За всеми ссылками и подробной помощью если заинтересуетесь обращаться в личку) Так же, я обладаю платой NodeMcu Lolin V3(Если грубо - это ардуинка с вай-файкой, но нет, это самостоятельный чип esp8266) В общем это всё, что нам сейчас понадобится(Еще понадобится роутер (и белый айпи, если вы играете на сервере)) Я хочу контролировать температуру своего реактора из IC2(но пристроить можно всё что угодно), поэтому берём его. Как это выглядит в игре: Схема реактора(Хотя ничего особо интересного тут нет): Переходим к реальному миру. Нам нужно открыть порт, в моём случае это 4536, к тому же нам нужен постоянный адрес в интернете. Для этого я использую DDNS. Об этом и остальном можно узнать в гугле. Теперь, всё готово чтобы наконец-то смотреть температуру реактора из реально мира! Есть такой простой код(Сейчас говорим про реальный мир): --Если кому будет интересно, вот полная документация по прошивке NodeMcu: https://nodemcu.readthedocs.io/en/master/ wifi.sta.config({ssid = "Xiaomi_2.4G", pwd = "xBfYHR33Le"}) --Мой SSID и пароль моего wi-fi =D wifi.sta.autoconnect(1) --Автоподключение Wi-Fi wifi.setmode(wifi.STATION) --Сейчас ESP8266 Будет работать в режиме клиента) spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8) --Настройка дисплея oled = u8g2.ssd1309_128x64_noname0(1, 8, 4, 0) oled:setFont(u8g2.font_haxrcorp4089_t_cyrillic) --Выставляем шрифт oled:setContrast(255) --Контрастность дисплея) server = net.createServer(net.TCP, 30) --Создаём сервер с тайм-аутом в 30 секунд по TCP протоколу function receiver(socket, temp) --Функция, которая вызывается при подключении oled:clearBuffer() --Очищаем буфер oled:drawUTF8(1, 7, "Темп. Реактора: " .. temp .. "%") --Пишем oled:sendBuffer() --Уже рисуем socket:close() --Разрываем подключение end server:listen(4536 , function(conn) --Выставляем на прослушку порт 4536 conn:on("receive", receiver) end) wifi_check = tmr.create() --Создаём динамический объект таймера wifi_check:alarm(1000, 1, function() --Эта функция - аналог event.timer в OpenComputers, которая так же вызывает функцию. В данном случае мы каждую секунду проверяем Wi-Fi. if not wifi.sta.getip() then --Если мы не имеем айпи, тогда wifi_connect = false oled:clearBuffer() --Очищаем буфер oled:drawUTF8(1, 7, "Подключение к Wi-Fi...") --Пишем oled:sendBuffer() --Рисуем elseif not wifi_connect then --Если мы только что подключились и не получили температуру реактора, тогда рисуем просто текст без температуры wifi_connect = true oled:clearBuffer() --Очищаем буфер oled:drawUTF8(1, 7, "Темп. Реактора: ожидание...") --Пишем oled:sendBuffer() --Рисуем end end) Код в майнкрафте(Очень простой): local component = require("component") local internet = require("internet") local reactor = component.reactor while true do local connection = internet.open("ip", 4536) connection:write(string.sub(reactor.getHeat(), 1, 2)) connection:close() os.sleep(5) end Теперь посмотрим что получилось! Подключение к Wi-Fi: Ожидание температуры: Итог: В общем то тут довольно всё криво сделано, тут надо много чего доделать, на самом деле. Но в целом, работает же=) Мне кажется, что это очень круто(Жаль что всё это без чанклодеров так себе работает). Такие дела. P. s @cyber01 Я сидел в редакторе долго, появилась ошибка "Произошла ошибка конфигурации или сервера". Пришлось вручную редактировать всё=(
  25. 8 баллов
    Обновление завез. Фиксы: Пимпочка скроллбара неправильно отображалась (окно с прокруткой сразу после отрисовки отображало пимпочку, несоотвествующую реальным размерам показанного контента) Юникод в поле ввода теперь поддерживается полноценно Папка рабочего стола изменена в связи с грамматической ошибкой (Desctop -> Desktop) Добавлено: Горячие клавиши. Клик + delete - файл удаляется, клик + ctrl + e - редактирование, клик+ctrl+e+delete - перезапись файла. Иконка батарейки в статусбаре - . (К сожалению, пока является статичным элементом) Техническое: файл настроек автоматически обновляется Изменено: Техническое: очистка кода в SetupWizard Техническое: частичный рефакторинг TabletOSGraphics. P.s. стараюсь выпускать обновления в первую субботу каждого месяца. До этого все изменения накапливаются в канале Experimental. В инсталлере этот канал есть, можете смотреть). Но там обычно немного нестабильно.
  26. 8 баллов
    Всем привет! Накануне я решил создать свой полноценный Банк, но пока я его делал, решил, что это будет карта на прохождение и специально допустил пару уязвимостей. (На самом деле я решил сделать карту на прохождение потому, что мне было лень их фиксить :d). Суть карты в том, что необходимо взломать банк и получить 10000$ на банковской карте. Уязвимости довольно скрыты и предстоит помучаться чтобы их найти, уязвимостей всего две. Первая - глобальная, средней сложности. Вторая - очень скрытая, высокая сложность. На карте так же реализовано подобие вышки, которое позволяет отправлять пакеты друг другу не напрямую, а через эту вышку. Так-же эта вышка помогает покрыть этим "интернетом" всю карту (необходимо поставить много вышек по всей карте) и преодолеть ограничение радиуса отправления пакетов. Банковская карта реализована RFID меткой. На карте присутствует банкомат, сервера, ваш домик и немного налички в сундуке. Правила карты (На вашу совесть, чтобы было интересно): Запрещается использовать компьютеры, кроме своего. (Просматривать логи сервера банка и сервера вышки на экране разрешено). Запрещается просмотр исходников серверов. Запрещается ломать блоки. (Карта в режиме приключения, но читы включены) Так-же имеется библиотека на вашем компьютере для работы с внутренним интернетом, находится она по пути: /lib/gsm.lua Строения на карте: 1. Вышка интернета. 2. ДЦ Сбербанк. 3. Офис Сбербанк. (Компьютер не трогать в нём) 4. Банкомат. 5. Домик кулхацкера. Подсказки по прохождению карты можно попросить у меня во ВКонтакте: https://vk.com/superrolan51 Ссылка на небольшой ролик по карте: Клик Ссылка на сборку: Клик Ссылка на портативную сборку от @Asior: Клик (Для версии Forge 1.7.10) Удачи в взломе! P.S. Не пишите в комментариях подсказки к карте
  27. 8 баллов
    По этой теме уже существует отлаженный софт, успешно используемый многими игроками. Однако на днях я заметил забавную особенность местных видеокарт, позволяющую выставлять разрешение большее, нежели получаемое через gpu.maxResolution(). К примеру, если maxResolution для видеокарты третьего уровня вернет числа 160 и 50, то никто не мешает установить разрешение, скажем, в 20x158 пикселей. При этом при проверке валидности устанавливаемого разрешения соблюдается два правила: Результирующее разрешение по числу пикселей не должно превышать результат умножения чисел, возвращаемых maxResolution. То есть для T3 GPU не более 160 * 50 = 8000. Каждый параметр разрешения, будь то ширина или высота, не должен численно превышать значение возвращаемой ширины. То есть для T3 GPU не более 160. Не знаю, баг это или фича, однако подобное грех не использовать в своих целях. К примеру, старая версия программы при вертикально-удлиненном расположении мониторов позволяла выставить разрешение лишь в 30х50 (1500 пикселей в итоге), заполняя тем самым "черные полосы". В то же время обновленная софтина, учитывающая описанные выше особенности, выдает 69x114 (7866 пикселей), максимально приближаясь к предельной отметке в 8000: Согласитесь, лишние пиксели на дороге не валяются, и, думаю, кому-то будет интересно узнать про реализацию подобного софта. Прежде всего нам требуется определить точную пропорцию мультиблочного монитора: то, как относится его ширина к высоте. Взглянем на текстуру блока: она явно состоит из мелких "квадратиков" в количестве 16 штук, причем лицевая часть монитора имеет рамку толщиной в 2 "квадратика" с каждой стороны: Эти "квадратики" мы и будем использовать для расчета пропорции, так как они позволяют идеально точно получить размеры отображающей части монитора в игровом мире. А размеры "в квадратиках" можно посчитать по формуле: число_блоков_монитора * 16 - 4 Следовательно, пропорция монитора будет считается следующим образом: local gpu = component.gpu local screen = component.proxy(gpu.getScreen()) local blockCountByWidth, blockCountByHeight = component.screen.getAspectRatio() local proportion = (blockCountByWidth * 16 - 4) / (blockCountByHeight * 16 - 4) Также не забываем, что высота каждого псевдографического пикселя при отображении в 2 раза больше его ширины, поэтому формула пропорции слегка меняется. Заодно произведем некоторые сокращения, чтобы избавиться от лишних математических операций. Все три варианта эквивалентны: local proportion = 2 * (blockCountByWidth * 16 - 4) / (blockCountByHeight * 16 - 4) local proportion = (blockCountByWidth * 16 - 4) / (blockCountByHeight * 8 - 2) local proportion = (blockCountByWidth * 2 - 0.5) / (blockCountByHeight - 0.25) После вычисления пропорции монитора можно приступить к написанию программной логики. Для начала получим максимальное разрешение видеокарты: local maxWidth, maxHeight = gpu.maxResolution() Обладая этими данными, а также взглянув на условия, описанные в начале поста, мы можем составить систему неравенств для получения итогового идеального разрешения: Помним также, что ширину мы вполне можем выразить через высоту и пропорцию монитора: width = proportion * height Подставим этот вариант в систему: Оставим высоту в левой части неравенств: Подставляем имеющиеся переменные в каждое неравенство, рисуем числовую прямую и выбираем высоту, удовлетворяющую условиям неравенства для конкретного случая. Разумеется, в программировании никаких числовых прямых нет, зато есть любимые math.min() и math.max(): local height = math.min( maxWidth / proportion, maxWidth, math.sqrt(maxWidth * maxHeight / proportion) ) -- Выражаем ширину через пропорцию local width = height * proportion Все. Разумеется, полученные значения ширины и высоты нужно округлить в меньшую сторону, дабы не кормить видеокарту дробями. Заодно добавим поддержку масштабирования, чтобы выставлять половинное или, скажем, четвертичное от идеального разрешение. Сократив код, избавившись от лишних переменных, мы получаем следующее: local component = require("component") -- Получаем масштаб в качестве первого аргумента скрипта и корректируем его значение local scale = tonumber(select(1, ...) or 1) if not scale or scale > 1 then scale = 1 elseif scale < 0.1 then scale = 0.1 end local gpu = component.gpu local blockCountByWidth, blockCountByHeight = component.proxy(gpu.getScreen()).getAspectRatio() local maxWidth, maxHeight = gpu.maxResolution() local proportion = (blockCountByWidth * 2 - 0.5) / (blockCountByHeight - 0.25) local height = scale * math.min( maxWidth / proportion, maxWidth, math.sqrt(maxWidth * maxHeight / proportion) ) -- Выставляем полученное разрешение gpu.setResolution(math.floor(height * proportion), math.floor(height)) Надеюсь, это микро-знание кому-то было полезно. Лично я очень доволен, что могу наконец запилить графонистый интерфейс для контроля реакторов на вертикальных мониках без осваивания профессии "глиномес", да и соответствующая либа для автопобора разрешения в оське пригодится.
  28. 8 баллов
    Помните мост Рида? Ну так вот. Я тут изучаю Rust на досуге, и пишу мини проекты. Так и получился у меня... Stem Это интернет мост для OpenComputers. Что такое мост Для тех кто не знает что такое мост, и для чего он нужен: мост дает примерно такие же возможности как и linked карта. Он позволяет связать между собой компьютеры OpenComputers, где бы они не находились. Только мост реализует это через интернет карту. Однако по сравнению с linked картой есть один очень крутой плюс. Вы можете подключиться к своему OpenComputers компу не только с другого OpenComputers компа из Майнкрафта, но и из реального мира. Например с телефона. Или с вашего домашнего компьютера. Отличие от моста Рида Я немного по другому подошел к архитектуре проекта. Вместо попарного соединения, Stem реализует систему каналов. Работает это очень просто. Вы можете: 1) послать сообщение в канал X 2) подписаться на сообщения из канала X Количество подписчиков не ограничено. Количество клиентов которые могут посылать сообщения в канал тоже не ограничено. ID канала (по которому происходит подписка и отправка сообщений) служит заодно и паролем к нему. Поэтому если вы хотите создать публично доступный канал - просто опубликуйте его ID. А если хотите создать свой, приватный, канал - просто возьмите ID подлиннее и никому его не открывайте. ID - это последовательность любых байт длиной до 256. Число комбинаций (256 в степени 256) это огромное число, так что уникальных ключей хватит надолго. Пример local event = require('event') -- подключаем STEM local stem = require('stem') -- присоединяемся к серверу STEM local server = stem.connect('stem.fomalhaut.me') -- просим сервер присылать нам сообщения с канала 'my-channel-id' server:subscribe('my-channel-id') -- слушаем эвент 'stem_message' в цикле while true do local name, channel_id, message = event.pull('stem_message') if name ~= nil then print(channel_id, message) end end -- ...или регистрируем листенер event.listen('stem_message', function(_, channel_id, message) print(channel_id, message) end) -- мы можем посылать сообщение в канал -- (причем не обязательно быть подписанным на этот канал -- достаточно просто его ID) server:send('my-channel-id', 'hello there') -- просим сервер перестать присылать сообщение с канала server:unsubscribe('my-channel-id') -- полностью отключаемся от сервера STEM server:disconnect() Одновременно можно работать с несколькими серверами Stem и с любым количеством каналов. Библиотека stem.lua Библиотечку можно скачать напрямую по этой ссылке: https://gitlab.com/UnicornFreedom/stem/raw/master/stem.lua Либо установить через HPM: hpm install stem Сервер STEM Дефолтный сервер STEM запущен у меня на VPS по адресу: https://stem.fomalhaut.me/ Можете смело его использовать. Единственное, что это тестовый сервер пока. Может пропадать или менять протокол. Новости постараюсь писать сюда. Исходный код проекта находится тут: https://gitlab.com/UnicornFreedom/stem Вы можете скомпилировать его под свою систему и запустить где угодно. Настраивается сервер файлом stem.toml в корневой папке. Дефолтный конфиг может выглядеть так: [tcp] host = '127.0.0.1' port = 5733 [web] host = '127.0.0.1' port = 5780 Чтобы получить полностью свой отдельный и независимый сервер STEM, достаточно будет просто запустить бинарник, получившийся после компиляции. Не забудьте также положить в папку с бинарником папки static и templates. Они нужны для веб-интерфейса. Сервер мультипоточный, и очень производительный. Должен тянуть довольно большие объемы трафика. Но точных бенчмарков я не проводил. Если есть желающие - пишите в IRC, скооперируемся и померяем. 😃 Веб-интерфейс Если перейти по ссылке на сервер STEM то вы увидите... какую-то хрень. Веб интерфейс еще не доделан, и пока просто показывает счетчик активных каналов и сессий в стиле Web 1.0. Доделать его и дополнить фишками - задача на будущее. Ну вот и все Мост в принципе уже полностью работоспособен. Что я хочу добавить в будущем: Клиент для Java / Rust (чтобы можно было подключаться к компу с телефонов на Android и с десктопов / серверов). Веб-интерфейс. Все идеи, пожелания, отчеты о багах пишите сюда, либо на issue трекер в репозитории. Enjoy! 😃
  29. 8 баллов
    Новости! Теперь мой браузер будет называться "Арбузер", и будет выполнен в зеленоватых тонах. Zer0Galaxy мне помогает, и уже набросал парсинг и поиск по самым простым селекторам в CSS. Думаю, ему для полной работы с CSS нужно будет написать еще разов в 6 больше кода. Готовы первые наброски самого браузера без страниц. Закладки, навигация, строка пути. Кстати, вы можете посмотреть эмулятор экрана компьютера из OC, который можно открыть в браузере и даже посмотреть исходный код. Ядро написано примерно на 15% пока что. В следующий раз буду отрисовывать элементы страниц, подгружая их стили.
  30. 8 баллов
    Вышла новая версия OpenComputers, в основном с самыми разными фиксами. Что изменилось: Моды теперь могут добавлять свои кастомные дискеты, которые можно получить перекрафтом их с ключом. (Vexatos) Две функции дебаг-карты: для отправки сообщения на другую дебаг-карту и отправки текста в буфер обмена какого-либо игрока. Опасная штука. (Vexatos) Когда роботы/дроны выкидывают что-либо в мир, они теперь посылают ивент. (Sangar) Добавлен новый предмет — MFU. Позволяет подключить к адаптеру любой блок, находящийся на удалении нескольких блоков. Это позволяет небольшие билды сделать красивее, а сложные схемы — удобнее. (Vexatos) Обновлён перевод на немецкий. (Vexatos) Обновлены LuaJ и JNLua — заявляется, что теперь всё лучше с UTF-8. (gamax92, Sangar) Обновление OpenOS. Как обычно, много изменений, но здесь опять уменьшение потребление памяти и увеличение производительности. (payonel) Дискета oppm теперь использует современные способы установки в OpenOS. А ещё программу обновили. (Vexatos) Обновление Plan9k. (magik6k) В планшетах не работал слот для карт, если было вставлено улучшение. (Vexatos) Очень труднонаходимый баг с экранами, которые после перезагрузки чанка (причём особенного) зависали, был ликвидирован. (Sangar) Больше не получится много раз потыкать ключом по дрону, чтобы получить большее их количество. (Vexatos) Устранены проблемы с вайлой (очень странная логика у неё) (Sangar) [MC 1.8.9+] При выкидывании предметов роботами или дронами некоторые уничтожались. (Vexatos) [MC 1.8.9+] Краш при использовании функции getName на нанонашинах. (Vexatos) [MC 1.9.4+] Компоненты могли не деинициализироваться, когда чанк с ними выгружался. Это приводило, например, к смене UUID компонентов. (Sangar) [MC 1.9.4+] Починили рендер клавиатуры. (Vexatos) [MC 1.9.4+] Команды ломали /help. (Vexatos) [MC 1.9.4+] В наномашинах не было эффектов зелий. (Vexatos) [MC 1.10.2+] Улучшена интеграция с JEI. (Vexatos) Релиз на GitHub.
  31. 8 баллов
    Программа Титан-2 – это еще один подход к построению добывающих программ с интерактивными возможностями и высокой степенью эффективности и автономности. Программа находится в режиме альфа тестирования и скоро будет доступна для скачивания. Код программы: Робот: скачать (в бета) Сервер: скачать (в бета) При разработке и написании программки я постарался руководствоваться следующими концепциями: длительное, практически неограниченное, время автономной работы быстрая процедура развертывания, свертывания, доукомплектования робота и определения задачи на местности, робот сам сориентируется на карте по навигатору, выйдет на нужную глубину бурения и буквально меньше чем через минуту уже начнет добывать ресурсы высокая степень мобильности и скрытности робота на местности работа на защищенных каналах связи простая процедура передислокации робота, смены рода деятельности выполнение поставленной задачи в условиях любой сложности максимальное использование систем и апгрейдов, дающих колоссальное преимущество роботу при выполнении необходимых задач (цель оправдывает средства) высокий уровень живучести, модульности и спектра применения робота минимальное вмешательство человека в работу программы дистанционный контроль постоянный мониторинг процесса работы, состояния робота и его систем максимально быстрый алгоритм поиска руд, вскапывания и добычи и минимальное количество операций записи, чтения и циклов, максимально быстрое и четкое перемещение поиск решений при возникающих проблемах самим роботом. Если робот нашел решение, он его принимает сам и не нуждается в человеке лог событий, полный анализ роботом своего состояния, и влияние их значений на дальнейшие действия робота максимальная «защита от дурака» и ввода неправильных данных и команд для обеспечения бесперебойной и правильной работы программы. По сути девиз такой: Поставил робота, дай ему инструменты и забудь про него. Только забирай ресурсы. Сразу скажу, что программка Титан-2 предъявляет достаточно высокие аппаратные требования к роботу. Нубасам, которые ноют, что в игре нет китов и дорого крафтить клавиатуру (ведь для нее нужен камень), а алмазы для микрочипов и дорогих плат найти вообще нереально сложно, эта программка не подойдет. :P Для игроков начального уровня на первых порах лучше использовать какую-нибудь примитивную каменную черепашку в режиме "эксквавектвайлетруду 3х3" или кирку и упорно голосовать 5 дней для покупки ЧЛ для робота =) Рекомендуемые аппаратные требования: Установка и настройка: (Описание, в релизе) Текущие возможности программы: несколько алгоритмов добычи и других задач, вызываемых из меню интерактивных очков одной командой (робот приступит к выполнению и больше не будет Вас тревожить) робот знает все предметы майна, нужные руды, мусор и прочее, Вам не нужно заботиться о том, что добывать, какие предметы положить, что выкидывать и т.д. Робот уже сам работает со списками и своей базой предметов и их свойствами робот умеет работать с инвентарями, знает все моды и предметы, которые можно использовать в качестве контейнеров (сундуки) автоматически и своевременно поддерживает себя на достаточном энергетическом уровне робот анализирует в инвентаре доступные наборы и предметы, инструменты и контейнеры, и не важно, как они там валяются, в каком порядке и из каких они модов своевременно меняет инструменты с низким уровнем заряда периодически чистит инвентарь, сортирует и укладывает предметы, ведет общий подсчет добытых ресов, шлет полный отчет о работе, координатах, проценте выполнения поставленной задачи и пр. при заполнении инвентаря (а это 64 слота, что составит 4096 шт. полезных руд при работе силком. С учетом того, что Вы положите стак любых сундуков и пару заряженных буров перед началом работы, немного меньше), робот начнет делать схроны (прятать ресы в сундуки) и записывать их координаты, при условии, что он найдет сундуки у себя в инвентаре. Если задача по буровым работам была не слишком объемной, сундуки можно не давать роботу. В любом случае, если сундуки закончатся или инвентарь заполниться, или все доступные буры (кирки, ломы и лопаты ) будут иметь запас прочности/заряда меньше 5%, робот приостановит свою работу и будет терпеливо Вас дожидаться, периодически Вас звать, пока Вы не дадите ему требуемое. Далее робот возобновит работу Вы можете посмотреть все тайники ресурсов с консоли, их собрать, а список тайников выборочно или полностью очищать дистанционно с консоли Terminal Glasses. в любой момент можно дистанционно прервать работу робота, вызвать его на любые координаты, переоснастить и переозадачить и перебазировать, при чем не обязательно находится возле робота. Все это можно сделать, не отрывая попки от телевизора и не выходя из своего домика процесс и управление осуществляется с Terminal GlassesóServer+связанная картаó связанная карта+робот. Бесперебойную работу робота, связь с ним и управление обеспечивает чанклоадер. Управление, контроль и мониторинг доступен из любого мира и не зависит от расстояния робот, благодаря наличию апгрейда, накапливает со временем опыт и работает все более эффективно сканирование ресурсов в толще породы осуществляется геосканером методом “фалангового сканирования” (“бегущий кластер”, “удар катаны” ) поддержка английской и русской локали предметов пр. Планируемые возможности программы: добавление разных видов строительных и добывающих работ более гибкая и разветвленная система команд, диалоговые окна для Terminal Glasses управление роботом и добычей ресурсов со своего смартфона на базе Android, контроль и мониторинг. При все при этом Вы можете добывать ресурсы, находясь на парах или в школе на уроках добавление возможности (при использовании серверной стойки) смены (выбора) контроля и управления над несколькими роботами методом биндинга связанных плат на основной канал моста через команду консоли TerminalGlasses др. возможности
  32. 8 баллов
    Здравствуй, брат автоматизатор! Желаешь ли ты услышать от меня несколько мыслей о красивом, понятном, и эффективном коде? На истину в последней инстанции я не претендую, и ты, возможно, знаешь решения получше моих. В этом случае оставь свои соображения в комментариях, и код на проекте станет немного чище. Небольшое отступление: Полгода назад я задумал написать серию статей о программировании для новичков, где я писал код и объяснял, почему он должен писаться так, а не иначе. Но такое объяснение оказалось для меня непосильным занятием, т. к. мне приходилось спорить с самим собой. Легко было только один раз, когда я обнаружил серьезный дефект, наверное, во всех копалках на проекте. Но потом я получил стрелу в колено... Вернувшись на проект, я неожиданно для себя понял, что демонстрировать эффективность удачного кода значительно проще, противопоставляя его коду неудачному. В прошлый раз я рассказал о том, как математика помогает писать более простые, понятные и при этом более эффективные программы. qwertyMAN заметил, что использование взятия остатка от деления – это не математическая проблема, и я с ним отчасти согласился. Решение о том, использовать или нет операцию %, мало влияет на общий алгоритм, но сильно влияет на то, как будет выглядеть готовый код. Но всё-таки об этой операции следует помнить уже на этапе проектирования алгоритма, а не только на этапе кодинга. А вот, о тонкостях написания кода я хочу рассказать сегодня, не особо вдаваясь в общие алгоритмы. Моим подопытным будет уже знакомый код из охранной системы турелей. Вот сам код: Первое, на что я обратил внимание – это использование pcall. Именно оно и побудило меня к разбору кода, но прежде я предлагаю обсудить другой нюанс. 1. Избегай повторения уже выполненных вычислений Имеются два фрагмента кода: if target and radar.getPlayerByName(target) then target=radar.getPlayerByName(target).all()...local mobif radar.getMobData(scan[i]).basic() then mob = radar.getMobData(scan[i]).basic() target = mob И в обоих фрагментах происходит дублирование вызовов. Первый раз вроде как для проверки. Но такой код всё равно не снимает проблему, т. к. при первом вызове функция может вернуть одно значение, а при втором вернет другое. Правильным решением будет сохранить результат в переменную. И если ее значение удовлетворяет условиям, использовать ее в дальнейшем. Во втором фрагменте следует заодно избавиться от переменной mob, которая больше нигде не используется. if target then target = radar.getPlayerByName(target) if target then target=target.all()...target = radar.getMobData(scan[i])if target then target = target.basic() Почему я проверяю результаты getPlayerByName и getMobData, а не других функций вроде all() или basic()? Потому что именно они могут вызвать ошибку. Ошибка возникает от того, что игрок или моб может покинуть зону действия сенсора, пока выполняется обработка внутри программы. К сожалению, указанной проверки недостаточно, т. к. мод OpenPeripheral вместо того чтобы вернуть nil или иным образом указать на проблему, тупо генерирует ошибку, не оставляя иного варианта кроме использования pcall. 2. Используй защищенный режим только там, где это необходимо Код программы выглядит примерно так: local function func() -- почти весь код программы помещен в эту функцию -- включая инициализацию переменных и определение функций ... -- этот бесконечный цикл прерывается из-за отсутствующей обработки ошибок while true do ... local target = false local scan=radar.getPlayers() ... target = ... if target and radar.getPlayerByName(target) then target=radar.getPlayerByName(target).all() ... end ... endend-- мегакостыль (комментарий самого автора)while true do local oop = pcall(func) print(oop)end Автор понимает, что использует костыль, но правильное решение использовать не хочет. Подобные городушки провоцируют появление новых: уже сейчас на ровном месте появилась дополнительная функция и вложение двух бесконечных циклов. Но главная проблема этого кода в том, что pcall скрывает любые ошибки, и дальнейшая отладка программы становится затруднительной. Даже печать результата, возвращаемого pcall, реализована неверно – ничего кроме false выведено не будет. Для решения проблемы следует использовать pcall точечно, только там, где это необходимо, а именно в вызове getPlayerByName и getMobData. А если есть возможность вообще обойтись без pcall, то в готовой программе без него следует обойтись. В нашем случае обойтись без pcall, похоже, нельзя. Поэтому убираем наш костыль и функцию func, оставив лишь ее содержимое, и дорабатываем проблемные участки таким образом: if target then local flag,res = pcall(radar.getPlayerByName,target) if flag then target=res.all()...local flag,res = pcall(radar.getMobData,scan[i])if flag then target = res.basic() Пришлось ввести дополнительные переменные, зато код избавился от костыля со всей его обвязкой, а ошибка, генерируемая модом OpenPeripheral, локализована, и новых проблем не создаёт. Программа работает стабильно и ее отладка не нарушена. На этом можно было бы и закончить, но я уже вошёл во вкус. Поэтому продолжу давать советы, иллюстрируя их фрагментами кода: 3. Выноси за цикл всё, что возможно Это правило подобно первому, но пренебрежение им не так бросается в глаза начинающего программиста, т.к. сам код не дублируется, зато дублируется его исполнение. Восстановим общий алгоритм работы программы, чуть подробнее разобрав этот кусок: while true do local target = false ... local scan=radar.getPlayers() if firePleayers and #scan>0 then if #White_Player_List>0 then добавление списка авторов в в белый список target = первый игрок на радаре вне белого списка elseif #Black_Player_List>0 then удаление авторов из черного списка target = первый игрок на радаре в черном списке else if #autors>0 then перенос авторов в белый список else target = первый игрок на радаре вычисление координат цели и выполнение выстрела сканирование мобов, вычисление их координат с последующим расстрелом. Как ты уже догадался по заголовку, в бесконечном цикле выполняется что-то явно лишнее. А именно, работа со списком авторов. Всё это могло бы прекрасно работать и до основного цикла, создавая при этом нужный эффект. Более того, вынос этого кода за цикл позволит исправить серьезнейшую ошибку: на каждой итерации бесконечного цикла происходит добавление авторов в белый список, при этом их наличие в белом списке никак не проверяется, но каждый раз происходит добавление новых. Даже с двумя планками памяти 3.5 уровня через сотню-другую тысяч итераций программа завершится с ошибкой «not enough memory». Вынося лишние действия за цикл, ты избавишь программу как от неконтролируемого расхода памяти, так и от лишних действий, замедляющих ее работу. Думаю, демонстрировать корректный код здесь излишне. Достаточно лишь вынести эти участки кода из цикла. В программе присутствуют и менее очевидные вычисления, которые можно вынести за цикл. -- этот код находится за цикломlocal correct = { x = 0, y = 4, z = 0 }...-- а этот внутриlocal x,y,z = target.position.x-0.5-correct.x, target.position.y+0.3-correct.y, target.position.z-0.5-correct.z...local x,y,z = target.position.x-0.5-correct.x, target.position.y-0.5-correct.y, target.position.z-0.5-correct.z Логичным будет переписать код таким образом: -- этот код за цикломlocal correct = { x = 0+0.5, y = 4+1, z = 0+0.5 }...-- а этот внутриlocal x,y,z = target.position.x-correct.x, target.position.y+1.3-correct.y, target.position.z-correct.z...local x,y,z = target.position.x-correct.x, target.position.y+0.5-correct.y, target.position.z-correct.z Так мы избавимся от лишних сложений и вычитаний в цикле. Лишние сложения при инициализации таблицы correct не сильно помещают, т. к. они выполняются всего один раз, а нужны они для наглядности кода. Поясню, что здесь происходит. Во-первых, турель и сенсор находятся в разных блоках, поэтому координаты игрока следует скорректировать на эту разницу. Координаты турели относительно сенсора хранятся в таблице correct. Во-вторых, сенсор определяет координаты игроков и мобов относительно своего северо-западного угла, а турель вращается вокруг центра блока. Поэтому приходится корректировать координаты (x,z) на половину блока по горизонтали. В-третьих, сама турель стреляет на один блок выше уровня ног игрока или моба. Автор корректирует высоту цели в зависимости от цели: для игрока прицел приподнимается на 0.3 блока, чтобы игрок не мог уходить от выстрела прыжком или прятаться за блоки, а для мобов прицел опускается на полблока, чтобы попадать, например, в кур или свиней. Но тут тоже не всё просто. Чтобы попадать в цыплят, прицел следует опустить еще ниже, но тогда турель промахивается мимо взрослых кур, стреляя им куда-то под ноги. Для эффективной стрельбы по любым мобам нужен алгоритм, определяющий вид моба, его возраст, и находящий по таблице его рост. Причем, нужен не только рост. Например, нет смысла целиться в нижнюю часть слизня, т. к. тот постоянно прыгает. В общем, это отдельная тема для поиска оптимального алгоритма, сейчас же я хочу продолжить рассказ о кодинге. В итоговом коде не только вынесены лишние вычисления из цикла. Кроме этого он стал более логичным: числа 1.3 и 0.5 по сути означают высоту цели относительно ног игрока или моба. 4. Прерывай циклы, когда они уже выполнили свою задачу Вот два подобных друг другу фрагмента кода: local swich = truefor j=1, #White_Player_List do if scan[i].name==White_Player_List[j] or not scan[i].name then swich = false endendif swich then...local swich = falsefor j=1, #Black_Player_List do if scan[i].name==Black_Player_List[j] then swich = true endendif swich then Задача циклов в том, чтобы при подходящем случае изменить значение переменной switch. Но как только оно изменилось, зачем продолжать работу? Далай break. Иначе выполнение твоей программы замедляется. Пока я писал этот текст, то напрягался при каждом наборе названия переменной swich. Нет такого слова, зато есть слово switch, и не глядя я набирал именно его. Поэтому буду писать switch. Кроме того, название переменной все равно не отражает ее сути. С тем же успехом можно было использовать однобуквенное название переменной. А лучше бы и вовсе избавиться от нее. 5. Избавляйся от лишних переменных Вот те же фрагменты в немного дополненном составе, внутри других циклов и с оператором break, как же теперь без него: local target = false...for i=1, #scan do local swich = true for j=1, #White_Player_List do if scan[i].name==White_Player_List[j] or not scan[i].name then swich = false break end end if swich then target = scan[i].name break endend...for i=1, #scan do local swich = false for j=1, #Black_Player_List do if scan[i].name==Black_Player_List[j] then swich = true break end end if swich then target = scan[i].name break endend Что выполняют оба фрагмента? Ищут подходящую цель по белому и черному спискам игроков. Где хранится цель? В переменной target. Что хранится в переменной switch? Флаг того, что переменная target должна быть изменена. А зачем нам этот флаг? Что мешает сразу изменить переменную? local target = false...for i=1, #scan do target = scan[i].name for j=1, #White_Player_List do if scan[i].name==White_Player_List[j] or not scan[i].name then target = false break end end if target then break endend...for i=1, #scan do for j=1, #Black_Player_List do if scan[i].name==Black_Player_List[j] then target = scan[i].name break end end if target then break endend Код стал немного короче и быстрее, но и это еще не предел. Еще непонятно, что делает, or not scan.name в условии. Повлиять это выражение может в том случае, если scan.name будет равно false, или nil. А разве такое возможно? Даже не знаю, как классифицировать этот недочет. Видимо, от старых экспериментов осталось. Посоветовать можно только одно: вычищать код перед публикацией. 6. Используй ассоциативные возможности таблиц Lua Таблицы в Lua – это больше чем массивы. Это и объекты, и списки, и словари. А может, и что-то еще, о чем я забыл или даже не знал. Таблицы в Lua – это наборы пар ключ-значение. В качестве ключей и значений таблицы может быть что угодно кроме nil. Пара ключ-значение в таблицах Lua присутствует даже если мы не используем ключи явным образом. Попробуй запустить такой код: PlayerList={"Ded", "Baba", "KurochkaRyaba"}for k,v in pairs(PlayerList)do print(k,v)endfor i=1,#PlayerList do print(PlayerList[i])endPlayerList={[1]="Ded", [2]="Baba", [3]="KurochkaRyaba"}for k,v in pairs(PlayerList)do print(k,v)endfor i=1,#PlayerList do print(PlayerList[i])endPlayerList={["Ded"]=1, ["Baba"]=2, ["KurochkaRyaba"]=3}for k,v in pairs(PlayerList)do print(k,v)endfor i=1,#PlayerList do print(PlayerList[i])endprint(#PlayerList)print(PlayerList["Ded"])print(PlayerList["Baba"])print(PlayerList["RedHatBaby"]) В первом случае мы не указываем ключи явно, но они создаются. Мы свободно перебираем как пары ключ-значение, так и значения по их индексу, который совпадает с ключом. Во втором случае мы явно указали ключи. Перебор пар ключ-значение показывает, что элементы таблицы хранятся в неведомом нам порядке, скорее всего, в соответствии с неким хешем, но на перебор по индексу это никак не влияет, порядок не нарушен, а это самое главное. В третьем случае мы поменяли ключи и значения местами. Естественно, ни о каком переборе по индексу теперь не идет и речи. Более того, определить длину таблицы теперь тоже не так просто. Зато появилась возможность, не выполняя перебор всех значений в цикле, одной командой определить, присутствует ли игрок в списке. Для игроков Дед и Баба есть значение, а игрок КраснаяШапочка в список не внесен, и имеет значение nil. Как это соотносится с нашим кодом? Попробуем заполнять списки игроков таким образом: local Black_Player_List = { ["qwertyMAN"]=1 } local White_Player_List = { ["Ded"]=1, ["Baba"]=1, ["KurochkaRyaba"]=1 } В качестве значения я использовал 1, и оно может быть любым, но 1 - записывается кратко. Главное, чтобы не nil. И не false, чтобы проще было выполнять проверку элемента. То, что qwertyMAN оказался в черном списке, ему никак не повредит, он же автор. Теперь все фрагменты кода изменятся таким образом: Добавление списка авторов в в белый список: -- былоfor i=1, #autors do White_Player_List[#White_Player_List+1] = autors[i]end-- сталоfor i=1, #autors do White_Player_List[autors[i]] = 1end Код немного укоротился, а главное – теперь переполнение памяти не грозит даже при работе в бесконечном цикле, т. к. элемент создается один раз, а в последующие – лишь изменяется его значение. Удаление авторов из черного списка: -- былоfor i=#Black_Player_List, 1, -1 do for j=1, #autors do if Black_Player_List[i] == autors[j] then table.remove(Black_Player_List,i) end endend-- сталоfor j=1, #autors do Black_Player_List[autors[i]] = nilend Код заметно укоротился. Сомневаешься, действительно ли элемент таблицы удаляется? Запусти этот код, и все станет понятным: PlayerList={["Ded"]=1, ["Baba"]=2, ["KurochkaRyaba"]=3}for k,v in pairs(PlayerList)do print(k,v)endPlayerList["Ded"]=nilfor k,v in pairs(PlayerList)do print(k,v)end И напоследок два уже разобранных перед этим фрагмента, которые еще более упростились: -- былоfor i=1, #scan do target = scan[i].name for j=1, #White_Player_List do if scan[i].name==White_Player_List[j] then target = false break end end if target then break endend...for i=1, #scan do for j=1, #Black_Player_List do if scan[i].name==Black_Player_List[j] then target = scan[i].name break end end if target then break endend-- сталоfor i=1, #scan do if not White_Player_List[scan[i].name] then target = scan[i].name break endend...for i=1, #scan do if Black_Player_List[scan[i].name] then target = scan[i].name break endend 7. Минимизируй идентичные участки кода При добавлении сходного функционала в программу можно скопировать рабочий участок кода и немного изменить его. Иногда до неузнаваемости. Но если фрагмент достаточно велик, а изменения малы, то правильнее будет вынести этот фрагмент в отдельную функцию. Во-первых, итоговой код будет более компактным. Во-вторых, при необходимости будет проще вносить изменения, не правя все участки кода. В программе имеется два таких похожих участка: local x,y,z = target.position.x-correct.x, target.position.y+1.3-correct.y, target.position.z-correct.zlocal vx,vy = pointer(x,y,z)turret.moveTo(vx,vy)if turret.isOnTarget() then turret.fire()end...local x,y,z = target.position.x-correct.x, target.position.y+0.5-correct.y, target.position.z-correct.zlocal vx,vy = pointer(x,y,z)turret.moveTo(vx,vy)if turret.isOnTarget() then turret.fire()end Ранее мы уже выяснили, что единственная изменяемая величина здесь – это коррекция высоты цели. Сейчас основной вопрос: что из этого следует вынести в отдельную функцию. С точки зрения минимизации кода следует выносить почти всё. Но чтобы сделать код более логичным, не следует всё мешать в одну кучу. Лучшим решением мне кажется вынос всего, что связано с вычислениями, в уже имеющуюся функцию pointer. Вот она: local function pointer(x,y,z) local distXY = math.sqrt(x^2+z^2) local distDY = math.sqrt(y^2+distXY^2) local outX = math.deg(math.acos(x/distXY))+90 local outY = 90-math.deg(math.acos(y/distDY)) if z<0 then outX = (180-outX)%360 end return outX,outYend Учитывая то, как я переписал эту функцию в прошлый раз, а также избавляясь от лишних переменных и перенося часть вычислений внутрь функции, перепишу код таким образом: local function pointer(pos,h) local x,y,z = pos.x-correct.x, pos.y-correct.y+h, pos.z-correct.z local azimuth=math.deg(math.atan2(x,-z))%360 local elevation=math.deg(math.atan2(y,math.sqrt(x*x+z*z))) return azimuth, elevationend...turret.moveTo(pointer(target.position,1.3))if turret.isOnTarget() then turret.fire()end...turret.moveTo(pointer(target.position,0.5))if turret.isOnTarget() then turret.fire()end Конечно, этот код можно ужать еще плотнее, но я увижу в этом смысл, если дальнейшая доработка программы вынудит меня продублировать эти блоки кода. На этом закончу. Возможно, я дал бы тебе еще пару советов, но за исключением описанных выше моментов код qwertyMAN'а вполне адекватен. Программируй красиво, брат!
  33. 8 баллов
    В прошлый раз мы научились подключаться к сети OpenNet, создавать простенький сайт и открывать его на локальном компьютере. Сегодня мы попытаемся получить доступ к сайту удаленно. Чтобы файл index стал доступен по сети, необходимо на сервере запустить специальную программу - WEB-сервер. В стандартный набор программ для работы с Сетью она не входит, но ее всегда можно скачать, выполнив команду: wget -f https://preview.c9.io/krutoy242/opennet/_source/WEB/WEBserver.lua webserv.lua Да, да, не удивляйтесь, именно wget, хоть в составе нашего компьютера и нет интернет-карты. После того, как мы подключились к Сети нам стали доступны все прелести интернет-карты даже при отсутствии оной, а всё благодаря крутому интернет-серверу, функционирующему в Сети. Pastebin, кстати, тоже работает. Загрузили webserver? Запускаем его. Мы должны увидеть вот такую картинку: Запомним IP-адрес нашего сервера (выделено на картинке). Он понадобится в первое время для подключения к серверу. Теперь идем к другому компьютеру, подключенному к Сети, и проверяем наличие связи с сервером: ping c0b.9cf.a4f Если у Вас нет второго компьютера, Вы можете воспользоваться любым свободным в нашем датацентре. Связь есть? Запускаем браузер с указанием адреса нашего сервера. onBrowser c0b.9cf.a4f Как видим, для открытия сайта по сети нет необходимости указывать не только папку /web, но и имя файла index. Дело в том, что папка /web считается корневой для нашего сайта. А если не указать имя файла, то по умолчанию сервер вернет файл index. Все остальные файлы придется указывать. Но я не хочу что бы к моему серверу обращались по ужасному IP-адресу. Хотелось бы имя покороче и лучше запоминаемое. Для этого нужно пройти регистрацию на DNS-сервере. Допустим, я хочу, что бы наш сервер назывался Zer0. Не слишком оригинально, но на первый раз пойдет. Имя это не должно содержать пробелы и конечно же должно быть уникальным, т.е. никто ранее не должен был зарегистрировать такое же имя. Так же не желательно, чтобы имя содержало точки и наклонные черты. В этом случае имя будет зарегистрировано, но в дальнейшем могут возникнуть проблемы с маршрутизацией. Как же происходит процедура регистрации? Можно, конечно, воспользоваться напрямую функциями DNS-сервера, описанными в теме http://computercraft.ru/topic/675-opennetoc-prodolzhenie/?do=findComment&comment=9097, но с некоторого момента я предпочитаю пользоваться утилитой setdns, которая входит в стандартный набор программ OpenNet. Эта утилита позволяет проверить не зарегистрировано ли еще DNS-имя, какие имена зарегистрированы на тот или иной IP, проводить собственно регистрацию или корректировать настройки уже зарегистрированного имени. В будущем планируется реализовать функцию удаления DNS-имени, но пока она не реализована. Первым делом убеждаемся, что выбранное имя еще не никем не занято (пункт 1). Затем запускаем процедуру регистрации (пункт 3). При регистрации необходимо указать желаемое dns-имя, IP-адрес, с которым это имя будет ассоциировано, и пароль. Пароль понадобится, если мы заходим перерегистрировать имя на другой IP. Если регистрация проводится с того компьютера, чей IP ассоциируется с dns-именем, на запрос IP можно ввести пустую строку. После регистрации выбираем пункт 0 для выхода из утилиты setdns. Теперь мы можем обращаться к серверу не по IP, а по удобному имени. Снова запустим webserver на нашем компьютере, а на соседнем onBrowser Zer0 В следующий раз я постараюсь рассказать как сделать наш сайт разноцветным и интерактивным. (продолжение следует)
  34. 7 баллов
    Дело было вечером, делать было нечего... И тут я случайно зажал горячую клавишу калькулятора, и меня осенило! А ведь калькулятора то для ОС никто не писал еще! Так появилась идея создания этого калькулятора. Что можно про него сказать? Базовый калькулятор который умеет выполнять стандартные математические операции. Требования к ОС: Видеокарта 2 уровня и выше Монитор 2 уровня и выше Компьютер/сервер любого уровня с установленной OpenOS Управление самое простое - мышкой. При создании программы была взята статья Псевдографические интерфейсы в OpenComputers и на основе кода из неё был создан калькулятор. Установка: version 0.2 pastebin -get PaVaRGcd Calculator.lua version 0.3 pastebin -get ZjCTrj5a Calculator.lua P.S. Выражаю благодарность @Doob за статью. Если найдете какие-то баги, недочеты, или возникнут идеи по улучшению, я всех с радостью выслушаю.
  35. 7 баллов
    Всем здрасти. Скрины: Клиент 1: Клиент 2: Лог сервера: Реализовано: Выдача IP Передача данных по выданым IP Регистрация/удаление доменов Получение IP адреса по домену То что хочется реализовать: Улучшить защиту, возможно сделать шифрование -Улучшить способ передачи данных между внутриигровыми IP Сделать библиотеку для пользовательских программ(С++, Java, Python, итп) для управления\получения данных OC через сервер, а так же поддержку Arduino(Можно будет выводить значения на экран подключеный к Arduino) Добавить поддержку децентрализации если в сети более 1 сервера(Можно будет делать межсерверные DNS-запросы) (Продолжение следует) Плюсы: Можно соединять OC компьютеры стоящие на разных MC серверах Быстрая работа сервера Минусы: Нужна оптимизация и поиск багов Плохая защита Исходники GitHub: https://github.com/TheConnBit/OpenComputersDHCP-DNS P.S. Там же объяснение всех команд, итп Исходники для ленивых (обновлено): Сервер (Запускать через консоль java -jar и лучше в отдельной папке): DHCP-DNS-Server.jar Клиентская библиотека: ddns.lua На скрине показано: подключение к серверу, выдача IP, регистрация домена, запрос IP домена, передача данных, получение, удаление домена, отключение Вообщем, сильно не пинайте за код. Если кто возьмется искать\найдёт баги или будут предложения что улучшить\добавить, пишите мне сюда или на почту bithovalsky@gmail.com Сначало была идея только DHCP сервера, но потом я накнулся на статью Programmist135: http://computercraft.ru/topic/1853-dns/ и реализовал DNS. Запущен DHCP-DNS сервер: 185.224.135.134:9999 Последние изменения: - - v1.1 Исправлены названия функций Исправлен перевод Функция Resolve теперь возвращает IP Пофикшены отключения сервером клиентов из за таймаута Echo запроса Список доменов теперь указывается в файле config.properties Изменён способ отправки сообщений по IP, появились порты --Bit
  36. 7 баллов
    Эм, здрассьте. Предлагаю поглядеть на новое обновление мода. Очень толстого обновления. Отрегулировали частоту выполнения хука, который шлёт этот ненавистный "too long without yielding", так что теперь и скорость исполнения кода должна гораздо возрасти, и с ошибкой этой код падать реже. Мы проверяли: некая гуи-либа с 1.6 fps до 2.5 fps только благодаря этому работать стала. Оптимизировали производительность ещё и записи на диск. Пошустрее будет — обещают, что в 5–500 раз. Сетевой разделитель (сплиттер) стал компонентом. Можно программно теперь отключать куски сети. Жёсткие диски стало возможным делать Read-Only. Компьютеры CC могут читать сигналы бандлед-редстоуна OC. И наоборот. Функции [il]debug.getlocal[/il] и [il]debug.getupvalue[/il]: возвращают они лишь только имя переменной, но не значение её. И мне кажется, что это уже давно было завезено. Геолайзеры получили методы [il]isSunVisible[/il], [il]canSeeSky[/il] и [il]detect[/il]. Неплохо. В [il]computer.beep[/il] можно писать морзянку. [il]computer.beep("---.---")[/il]. [il]redstone.setOutput[/il] научился ставить значения больше 15. Клавиатуру можно цеплять к монитору, если ещё поставить к непередней стороне блока. Наконец-то. [1.12] Вернули поддержку Project Red. Через адаптер можно теперь работать с камерой реактора IC2. У серверных дисководов тоже есть теперь гуишка (пкм в мире или внутри интерфейса стойки). Торговый апгрейд обзавёлся методом [il]getMerchantId[/il]. Полезно, если жителей куча. [1.12] Вернули поддержку энергии AE2. В конце-то концов: дебаг-карте добавили [il]scanContentsAt[/il]. Больше инфы возвращается для предметов из Draconic Evolution. Вейпоинты стало можно ставить вверх или вниз. Это действительно было слишком контринтуитивным. Связанные карты можно скрафчивать вместе (повяжет на новый канал их). Плюс получать адрес канала при скане стэка. Можно теперь менять цветовой код сундуков Ender Storage. Связанные карты также научились будить компьютер по сигналу, как модемы. Белый и чёрный списки измерений для чанклоадера. Метод [il]disk_drive.media[/il], которым можно получить адрес дискеты внутри дисковода. Поддержка Forge Energy для зарядки предметов вроде батареек и планшетов. Анализатор показывать будет по клику на адаптер ещё и содержащийся в нём компонент. Событие [il]redstone_changed[/il] показывает, какой цвет поменялся на бандлед-кабеле. По шифт-клику компоненты закидываются в соответствии с их уровнями. Подрезали немного шум в логе от OC. Методы вроде [il]robot.suck[/il], [il]robot.suchFromSlot[/il] и [il]transpoer.transferItem[/il] теперь возвращают вместо [il]true[/il] число перемещённых предметов. Немного уменьшили назойливость частиц наномашинок. Жёсткий диск 3 уровня в режиме без ФС стал иметь по умолчанию не 6, а 8 пластин. Улучшили рендер кабелей как-то. Такие же "как-то" улучшения произошли с инвентарём роботов, апгрейдом крафта, методами [il]swing[/il] и [il]use[/il], взаимодействием с жидкостными баками. С модами получше работать должны. Чанклодыри можно ставить в микроконтроллер теперь. Расширили покрытие юникода шрифтом. Стандартный биос стал есть меньше памяти. Мониторы глючить должны поменьше. Пофиксили обнуление содержимого инвентарей блоков мода при крашах. Ещё некий краш при установке микроконтроллеров починили. Команду [il]/oc_nm[/il] вправили в место и заставили работать. Дюп роботов убран. Команды перемещения теперь говорят, успешно или безуспешно вызов завершился. Форсирование [il]LuaJ[/il] не форсировало эту архитектуру. [il]transferItem[/il] проверял не ту сторону. Починили Unknown error при попытке залить чего-то в некие машинки. Дюп дронов тоже починили. Выкорчевали возможную ошибку при запуске вместе с IC2. Роботы перестали потреблять ингредиенты при крафте, которые не потребляются. Апгрейд ангельский стал работать. Пофиксили торговый апгрейд. Его прямая задача исполнялась кривовато. Роботы не перемещались, когда нужно было. Дюп предметов дронами и роботами. Дискету network тоже можно ставить через install теперь. Дюп жидкостей, конечно, тоже был и тоже пофикшен. Дроны не реинициализировались после включения по сообщению модема. И вели себя очень странно. Всякие фиксы в интеграции с AE2. Опять некий дюп EEPROM. Удалён. Краши при загрузке с Applied Llamagistics. Краши при нетрадиионной установке компьютеров. Краши (но на клиенте), связанные как-то с кабелями и загрузкой чанков. [il]enableNanomachinePfx[/il] не имела эффекта. Роботы стали вызывать обработчики модов при получении опыта. Вводящие в заблуждение сообщения анализатора о выключенных компьютерах стали вводить в заблуждение в меньшей степени. Микроконтроллеры свою начинку теперь тоже выключают вместе с собою. Всякие ошибки кидал апгрейд поводка вместе с некоторыми модами. Фиксед. [1.10+] Починен рецепт крафта карточки с мировым датчиком. Экран планшетов теперь не зависает. Терминальные серверы ненормально цепляли удалённых терминалов на себя. Ошибки освещения с шейдерами. В OpenOS ещё отметить можно: Команда [il]reset[/il], которая ресетит разрешение. Ошибки сервисов пишутся в /tmp/event.log. Можно теперь ловить ошибки по Ctrl-Alt-C (жёсткие прерывания) путём переопределения функции в [il]process.info().data.signal[/il]. Копипаст в [il]edit[/il]: Ctrl-K — вырезать, Ctrl-U — вставить строку. Процессы закрывают файлы при завершении. Ссылочка на гитхаб, откуда можно скачать мод.
  37. 7 баллов
    С переменным успехом работа продолжается: Перенес основную логику на сангаровский JNLua вместо LuaJ, добавил лимитирование оперативки Переосмыслил систему виртуализации: теперь каждая машина - это отдельное окошко со своими параметрами, сохраняемыми в конфиге Запилил опцию изменения пропорций виртуального экрана для screen.getAspectRatio(), а то эмуляторы обычно выдают 1, 1 по дефолту Реализовал компонент tunnel, который, в общем-то, ничем не отличается от модема. Возможно, если нервы не сдадут, в будущем добавлю систему энергозатрат - и тогда связанная карта будет жрать овердофигища ресурсов Сделал выбор имени игрока, от лица которого осуществляется управление компом Добавил фичу скрытия тулбара справа, чтоб ничто не отвлекало взор, так сказать Багов, конечно, жопой жуй: не всегда корректно читаются файлы в бинарном режиме, многие фичи по типу computer.addUser() являются не более чем функциями-заглушками, а еще странно читаются экранные события при вертикальной ориентации. Ну, по крайней мере, опенось уже запускается. И гляньте, какой чудный FPS:
  38. 7 баллов
    Добавлено Версия дисковода гибких дисков (дискет, если что) для серверов. Возможность взаимодействовать с некоторыми хранилищами предметов с помощью контроллера инвентаря (не особо понял, что тут нового. Видимо, новые инвентари или черех адаптер). Поддержка энергии RotaryCraft. Возможность задать границы вывода (я про viewport, да) на GPU, так что теперь можно химичить с производительностью всякими нестандартными путями. Кабели запоминают цвета, в которых их красили, при срубании. Можно их теперь ещё и в сетке крафта красить. Интеграция с IC2 на 1.8.9. Можно переключаться между всеми лут-дискетами, перекрафчивая их с ключом. computer.getDeviceInfo() — метод, который возвращает базовую инфу об устройствах (от планок памяти до всяких шифраторов CX). computer.getProgramLocations() — функция, которая возвращает, на каких лут-дискетах какие лут-программы лежат. Торговый апгрейд для роботов. Торговля с жителями, об этом я уже писал. Можно задать свои HTTP-хедеры вместе с, ммм, HTTP-запросом. debug.playSoundAt, которая, как ни странно, играет звуки. Возможность задать используемый CPU из AE2 при запросе на автокрафт. Интеграция с ThaumicEnergistics. Цветные дронотапки (hover boots). Индикатор сетевой активности на серверах. Перевод на бразильский язык. [*]Изменено Мажорнейшее и вообще самое основное — серверные стойки. Я о них писал, да. Удалённые терминалы (Remote Terminals) подключаться должны к серверу удалённых терминалов (Remote Terminal Servers), штучке для серверной стойки. Компонент дисководиков. Можно теперь программно выкидывать диски из дисководов. Нёрф геолайзера — учитывается теперь дистанция до блока, а не колонны. Зато область сканирования можно задавать не только в виде колонны, а в виде кубоидов объёмом до 64 блоков. Упрощены рецепты. Новый шрифт поставлен. Можно сменить ещё с помощью ресурспаков. Один солидный книжный том изменений в OpenOS. [*]Починено Зависания при крафте, возвращающем тот же предмет, что и данный на входе. Всякие проблемы с рецептами режима грега. Обработка userdata в LuaJ. Конвертация энергии некоторых модов. Проблемы производительности из-за слишком усердной компресси данных, передаваемых клиенту. Тоже проблемы производительности, связанные с отправкой пакетов с дескрипторами компьютеров на клиенты. Обновление LuaJ с фиксами багов. Интеграция с Mystcarft. Напомню, категория "починено". Интеграция с ключом BuildCraft. Роботы могли черпать блоки текучих жидкостей, не источников. Генератор поедал нещадно предметы, если они не были вовремя оттуда вынуты. Контейнеры апгрейдов никогда не выпадали из планшетов при разборке. Сломанный код сохранения информации о блоках OC в версиях MC выше 1.8. Микроконтроллеры ловили только сигналы с сетевой карты. Вот это всё и есть OC 1.6. Вот чем он так крут по сравнению с прошлой версией. Ченджлог на страницу! Со времени первого коммита OC 1.6 до текущего момента прошло 465 дней. Это год и 100 дней. И ведь всё это время я ошибочно думал, что вот-вот, немного подождать, и будет 1.6.0, пару изменений ещё только. Здесь оригинал списка гигантского и ссылки на скачивание. У меня есть несколько записей, посвящённых обновлениям в этой версии. Если ещё их не читали, рекомендую ознакомиться.
  39. 7 баллов
    В последних версиях OpenComputers обрастает всякими загадочными вещами. Игроки, которые только только освоились с предыдущей версией вдруг понимают, что надо изучать все заново. "А пошло оно все!" - думают игроки, и уходят на версию 1.3.6, или переучиваются на ComputerCraft, который проще, и не требует непонятного. А одна из самых загадочных - неведомый EEPROM. Это такая мелкая хрень, без которой не работает ни один компьютер, или даже робот. Хорошо еще, что есть стандартный EEPROM который называется Lua BIOS. Он легко крафтится и заставляет работать компьютеры как и раньше. Но найдем задачку посложнее, где Lua BIOS не поможет. Попробуем собрать микроконтроллер, который будет управлять входными дверями. 1. План Представим, как оно должно работать. Слева от двери (если входить) - микроконтроллер. Ради понтов, возьмем Микроконтроллер 2-ого уровня и поставим в него беспроводную сетевую плату. Кроме того добавим красную плату, чтобы управлять дверью. 1. Если контроллер принимает сигнал "open" - он открывает дверь. 2. Если примет сигнал "close" - он закрывает дверь. 3. Если примет посторонний сигнал - взрывает динамит. Дабы сокровища не достались хакерам. Для управления задействуем любой комп, у которого тоже будет беспроводная плата (или точка доступа). 2. Крафтим контроллер С этим проблем не возникнет. Потому, что я играю в креативе :P . Открываем NEI и берем нужные детали. В последний слот положим пока пустой EEPROM. Потом поставим на него прошивку, а пока - не важно. Нажимаем кнопку "Старт" и достаем готовый блок. 3. Готовим прошивку Теперь, когда все готово, мы построили сокровищницу и скрафтили контроллер - осталось самое главное. Программирование EEPROM'а отличается от программирования обычной программы. Потому, что обычно, наши программы выполняются в OpenOS, которая заботливо загружает нужные библиотеки, предоставляет всякие удобные фичи и прочее. Тем не менее писать мы будем именно в OpenOS. Запустим компьютер, напишем edit bios и введем следующие строки: red = component.proxy(component.list("redstone")())while true do red.setOutput(5, 0) computer.pullSignal(1) red.setOutput(5, 15) computer.pullSignal(1)end Дело в том, что большая часть библиотек, которые мы использовали - это библиотеки OpenOS. А значит мы не можем ими пользоваться в BIOS. Однако кое-что нам доступно. Это библиотеки computer и component, и соответственно все установленные в целевом агрегате (микроконтроллер) компоненты. Более чем достаточно для наших задач. Вышеприведенный код делает следующее: * ищет компонент с названием "redstone" и возвращает его прокси * в вечном цикле посылает нулевой редстоун-импульс направо (side = 5), т.е. гасит сигнал * ждет секунду (на самом деле - ожидает эвентов, то есть сигналов) * посылает редстоун сигнал с силой 15 направо * опять ждет секунду Преследуем двоякую цель: во-первых проверить, что EEPROM вообще работает так про него написано на Вики. Кто его знает? А во-вторых: убедиться, что сторона 5 это именно та сторона, где дверь. А не какая-нибудь другая. Нажмем Ctrl+S, чтобы сохраниться и Ctrl+W, чтобы закрыть редактор. Вставим пустой EEPROM (еще один) в слот нашего компьютера, вместо лежащего там Lua BIOS. И напишем в консоль такую команду: flash -q bios MCBios Программа flash предназначена для прошивки чипов. Флаг -q говорит ей, чтобы не задавала лишних вопросов, затем идет имя файла с нашим кодом (bios) и метка, которую программа шлепнет на чип (MCBios). Все. Доставайте. Lua BIOS на место класть не обязательно, ибо этот слот нам еще потребуется. (Но не забудьте его вернуть, если будете перезагружать компьютер) Чтобы заменить пустой EEPROM в контроллере на наш MCBios, надо положить контроллер и MCBios на верстак. При этом пустой чип вылетит, а новый встанет на его место. Поставим контроллер на пол и протестируем. После клика ПКМ на контроллере - замигала правая лампа. Значит все работает как нужно. 4. Теперь - серьезно Извлеките чип с MCBios обратно (так же как и вставляли, только наоборот). Или приготовьте новый пустой чип. Главное - не запутайтесь в них. Пишем клиент для контроллера. У меня он выглядит примерно так: red = component.proxy(component.list("redstone")())modem = component.proxy(component.list('modem')())modem.open(27)red.setOutput(5, 0)red.setOutput(2, 0) -- no explosions yet =)while true do name, _, sender, _, _, message = computer.pullSignal(2) if name == 'modem_message' then if message == 'open' then red.setOutput(5, 15) elseif message == 'close' then red.setOutput(5, 0) else -- hacker tries to get? red.setOutput(2, 15) -- fire in the hole!!! end endendmodem.close() Все согласно плану. Прошиваем чип, вставляем в контроллер, а контроллер ставим слева от дверей. Сзади к контроллеру осторожно прилаживаем запал. ПКМ! Теперь открываем новый файл на компьютере: edit send И пишем в него такой код: local com = require('component')local modem = com.modemlocal args = {...}modem.broadcast(27, args[1])print("Message '"..args[1].."' sent!") Сохраняем, и закрываем. Это будет программка для тестирования контроллера. 5. Тест! Пишем в консоль send open. Дверь открылась! Пишем send close. Дверь закрылась! Пишем send opeh Упс! Опечатка. О_О
  40. 7 баллов
    Иногда случается такое, что ваши компьютеры расположены на расстоянии большем, чем стандартные 400 блоков. Wi-Fi отказал, а вам надо связать компьютеры по сети. Какие тут есть варианты? 1) Повысить лимит в конфиге. Это просто, но не всегда возможно. 2) Использовать linked карту. С её помощью можно пробить любое расстояние, да. Но тут есть несколько своих проблем. Она связывает компьютеры только попарно. Для связи нескольких компьютеров надо уже делать сложную систему проброса сообщений. Она занимает дополнительный слот. И т.п. 3) Использовать цепочку Wi-Fi карт Казалось бы, чем это проще второго варианта? А проще оно тем, что тут есть уже готовые библиотеки. =) Интермедия Когда-то в стародавние времена, когда трава была зеленее и птички пели громче, собралась на нашем сервере компания крутых парней и написала OpenNet. Это была полноценная компьютерная сеть. Этакий местный интернет. Она обладала своей строгой и надёжной топологией. Каждый узел - своим местом и адресом в сети. Никакой анархии. Хочешь - в чатике общайся. Хочешь - сайты строй. К сожалению, исходники и гайды до сих пор разбросаны по частям по всему форуму. Чтобы собрать это снова вместе, потребуется немало усилий. Да и зачем нам поднимать полноценный "интернет", если всё, чего мы хотим - это пробросить парочку сообщений туда-сюда? Поэтому в более новые и не такие добрые времена (птички потише, трава потускнее), некто Totoro и fingercomp придумали систему попроще и погибче. И назвали её Zn. Приступаем к решению Итак, как нам связать Васю и Олю, которые живут на противоположных краях Земного Блина? 1) Через микроконтроллёр Самое дешёвое в плане ресурсов решение - собрать микроконтроллёр, прошить его и закопать где-нибудь в лесу на полпути между Васей и Олей. Сначала нам потребуется код прошивки. Он идёт в комплекте с Zn библиотекой. Как цивилизованные современные люди, мы скачаем её с Hel-репозитория: hpm install zn Теперь в папке /usr/share/zn/ у нас есть файлик eeprom.lua. Который мы и прошиваем на чистый EEPROM: flash -q /usr/share/zn/eeprom.lua "Zn node" Всё. Осталось вставить чип в контроллер, включить его и закопать. Сеть создана! 2) Через компьютер Более солидное и основательное решение. Строим в лесу будку. В будке ставим компьютер. На компьютер устанавливаем OpenOS и HPM (если он не идёт в комплекте). Снова качаем библиотеку: hpm install zn Создаём мини скрипт: edit node.lua Пишем в нём такой код: (require ('zn')).connect() Сохраняем, выходим, запускаем его: node Всё! Скрипт выполнится и завершится, а в фоновом режиме останется работать демон Zn-сети, который будет пробрасывать сообщения. По желанию можно сделать скрипт более сложным - например выводить на экран сетевой трафик и другую полезную инфу. Также можно добавить скрипт в автозапуск компьютера, чтобы даже неожиданные сбои питания (белка залезла в трансформатор) не смогли повалить сеть. Эти два варианта обладают некоторыми недостатком, конечно. Чтобы ретранслятор работал автономно, надо ставить чанклодер и источник энергии. Однако, в силу своей гибкости, Zn сеть можно организовать и по другому. Поднять, так сказать, "лайт версию" ретранслятора. 3) Через планшет Устанавливаем на планшет OpenOS и ставим библиотеку и скрипт по методике #2. Далее, вручаем планшет соседу Пете и забиваем ему стрелку в том самом лесу. На протяжении X минут (где X зависит от терпения Пети) у вас будет полноценная сеть! Игрок будет служить чанклодером, а батарея планшета источником питания. 4) Через робота Строим робота, устанавливаем скрипт по методике #2. Затем ставим робота где-нибудь в незаметном месте (можно спрятать в кроне дерева, так чтобы свет солнца падал на солнечную батарею). Всё, мобильный ретранслятор готов. Если чанклодеры к роботам разрешены, он может существовать автономно долгое время, питаясь солнечной энергией. 5) Через дрон Прошиваете EEPROM как для микроконтроллёра, заряжаете в дрона. Дрона запускаете в свободный полёт над лесом. Готово! Хотя чанклодер всё равно нужен. Так что вам наверное придётся пастись где-то рядом. Этот вариант самый сложный, потому что если вы хотите управлять дроном (например, с планшета) то вам потребуется модифицировать прошивку и добавить блок управления. Зато запустив 1000 дронов, вы можете почувствовать себя Илоном Маском, или Цукербергом, раздающим Интернет папуасам. А как теперь этой сетью пользоваться? Все просто. Это делается почти как с обычным модемом. Только вместо модема вы используете библиотеку Zn. Если вы знаете адрес модема адресата - можете послать сообщение прямо на него. И не важно, через сколько промежуточных узлов оно должно будет пройти. До тех пор пока адресат в радиусе досягаемости хотя бы одного узла вашей сети - он ваше сообщение получит. -- подключаем библиотекуlocal zn = require('zn')-- коннектимся к сетиzn.connect()-- посылаем Оле сообщениеzn.send("адрес модема Оли", "сообщение для Оли")-- при завершении программы не забываем закрыть коннект-- (можно и не закрывать, но зачем тратить ресурсы компа зазря)zn.disconnect() Ну а если адресат неизвестен, можно кинуть сообщение бродкастом. Тогда его получат все, кто подключен к сети. И адресат, конечно тоже. local zn = require('zn')zn.connect()-- посылаем сообщение всем, кто подключён к сети (Оле в том числе)zn.broadcast("сообщение для Оли")zn.disconnect() Удачи в построении своих сетей. Enjoy Zn!
  41. 7 баллов
    Нашел эту табличку на англоязычном форуме по OpenComputers. Картинка за авторством Eunomiac показывает весь 8-битный диапазон цветов, доступный для отображения на алмазном дисплее. Пользуясь схемой, легко подобрать цвета для вашего интерфейса, и тут же составить к ним шестнадцатеричный код.
  42. 7 баллов
    Приветствую Вас, уважаемый читатель! В самый ТРУДный день '15 года я, наконец, написал красивые часы, которые идеально подходят для декорирования, например, метро или аэропорта, а также как просто инфо-панель дома Не будем отрывать коту хвост, закончим здесь предисловие. Finger Clock v. ∞ Простая прога для OpenComputers, которая будет показывать Вам текущее майновремя... и реальное время с поддержкой часовых поясов! Pastebin: http://pastebin.com/aKjh5SZL Command: pastebin get aKjh5SZL clock Минимальная комплектация: Монитор T1 x1 Компьютер T1 x1 Жёсткий диск T1 x1 + OpenOS Видеокарта T1 x1 Редстоун-карта T1 x1 (требуется, если монитор не поддерживает клик мышкой, то есть если монитор первого уровня. В мониторах выше не обязателен). Процессор T1 x1 ОЗУ T1.5 x2 EEPROM — Lua BIOS Интернет-карта/OpenNet-интернет — только для установки Рекомендуемая комплектация: Монитор T2/T3 x6 Компьютер T2/T3 x1 Жёсткий диск T1 x1 + OpenOS Видеокарта T2/T3 x1 Редстоун-карта T1 x1 (требуется, если монитор не поддерживает клик мышкой, то есть если монитор первого уровня. В мониторах выше не обязателен). Процессор T2/T3 x1 ОЗУ T2/T2.5/T3/T3.5 x1/2 EEPROM — Lua BIOS Интернет-карта/OpenNet-интернет — только для установки Функции: Позволяет показывать реальное время и внутриигровое время. Настройка цветов, разрешения и часового пояса в константах в начале программы. Не использует отдельные библиотеки — меньше возни с установкой. Настройка: В самом начале программы есть список констант для настройки программы. MT_BG = 0x000000 -- Цвет фона при режиме показа внутриигрового времени.MT_FG = 0xFFFFFF -- Цвет текста при режиме показа внутриигрового времени.DAY = 0xFFFF00 -- Цвет надписи "Day".EVENING = 0x202080 -- Цвет надписи "Evening".NIGHT = 0x000040 -- Цвет надписи "Night".MORNING = 0x404000 -- Цвет надписи "Morning".RT_BG = 0x000000 -- Цвет фона при режиме показа реального времени.RT_FG = 0xFFFFFF -- Цвет текста при режиме показа реального времени.TIMEZONE = 0 -- Часовой пояс (от -12 до 12).W, H = 80, 25 -- Разрешение экрана. Рекомендуется 40x8.REDSTONE = false --[[ Если параметр будет установлен в true, программа будет сменять режимы при изменении редстоун-сигнала. ]]--TOUCH = true --[[ Если параметр будет установлен в true, программа будет сменять режимы по клику мышкой по экрану. ]]--KEY1 = 13 -- Коды клавиши. По умолчанию — [Enter].KEY2 = 28 -- Подробнее в комментариях.AUTOMODE = true --[[ Режим, который активируется при запуске программы. true — режим внутриигрового времени, false — режим реального времени. ]]--SHOWSECS = true --[[ Позволяет скрывать секунды в режиме реального времени при значении, равном false. ]]--SWDATEMT = true -- Показывать внутриигровую дату.SWDATERT = true -- Показывать реальную дату.SWDTMMT = true -- Показывать внутриигровое время суток.SWDTMRT = true -- Показывать реальное время суток. Скриншоты: Режим показа внутриигрового времени Режим показа реального времени
  43. 7 баллов
    Я сосчитал все ресурсы необходимые на "рекомендованного" робота. Вставь в статью.
  44. 6 баллов
    Новые солнечные апгрейды(аддон к Opencomputers) выведут роботов на совершенно новый качественный уровень. Роботы станут почти автономными и смогут работать практически неограниченное время (если, конечно, робот будет проверять время суток, видимость неба и текущий заряд и вовремя всплывать на поверхность для подзарядки) Продвинутая, гибридная, ультимейт и квантовая панели обеспечат роботов и дронов неисчерпаемой энергией. Также аддон добавляет потрясающую и невиданную до сегодняшнего дня новую фичу - зарядку своих инструментов при необходимости прямо внутри инвентаря. Позитронный мозг робота/дрона программно уже сам сможет решить, по каким электрическим цепям ему в данный момент необходимо перенаправить могучие потоки энергии - в бур, в электро-краник для гевеи или в любой другой инструмент, который у него в инвентаре, или же в Главный аккумулятор, а при необходимости и направить всю свою мощь и энергию в миллионы ГВт для колоссального удара Теслой и разрушения на кварки всей живой материи в радиусе при опасности и при обнаружении врага на радаре. "Живучесть" и автономность роботов увеличивается на порядки. Также вы можете использовать своего робота в дальних путешествиях и просто дать ему подзарядить джетпак и свои квантовые или нано трусы, если они вдруг внезапно разрядились. Некоторые солнечные апгрейды, конечно же, не дешевые в крафте, но они того стоят. Роботы, наконец-то, шагнули в квантовую эру благодаря новым источникам энергии и новому аддону. Прощайте, архаичные ванильные угольные апгрейд-чайники. Вы хорошо послужили нам, но прогресс идет вперед. Уже приближается звук ударов иридиевых буров из шахт и слышится жужжание квантовых роботов и свист дронов. Замысел, геймдизайн: Alex Java кодинг: Neo
  45. 6 баллов
    Уважаемые игроки! Просьба принять участие в тестировании Персонального загрузчика чанков (аддон для Opencomputers) на сервере EvilWorld, который работает только при онлайне хозяина. Апгрейд только для робота и дрона. На данный момент установлен лимит на одного игрока: 3 одновременно работающих загрузчика. Каждый загрузчик грузит область 3 на 3 чанка. Разработчик аддона: vx13 Все наблюдения и результаты по работе данного апгрейда просьба оставить в этом топике или на github разработчика.
  46. 6 баллов
    Ой, забыл xD Спойлеры делать не умею. так что как-то так пока. Возможно на скриншоты слишком новые и из разрабатываемой версии.
  47. 6 баллов
    С недавним (1.5.18) релизом OpenComputers появилась такая хрень — наноботы. Посмотрев ролик от автора мода (он будет внизу статьи), было ясно, что запутался или я, или автор. Скорее всего первое. Потому решил отложить их на потом. И вот, пришло то время. По-быстрому забежав на тестовый сервачок и поигравшись с ними, понял, насколько чудовищно... КРУТЫ эти мелкие штуки. Почему? А сейчас узнаем. I. Тварелогия. Вообще, я немного наврал со словом "сейчас". Обосновывать будем по ходу развития сюжета, а в конце (нет, в середине!) сделаем вывод. Итак, вот вам выдержка из статьи по нанороботиксам. Нанороботы, наноботы, наномашины, наноиды, наниты, наномиты и иже с ими (будем использовать несколько обозначений в этом гайде) — это такие мелкие штуки, которые попадают в организм кубического человека и жрать, мозги, хлам! помогают ему обрести новые способности. II. Приборы и девайсы. Значит так, в процессе эксперемента нам нужно: желание умереть, мозги, больше мозгов, невероятное желание подохнуть, планшет, наноботы, грог (?!). III. Ход эксперимента. Физ. часть. Итак, вы подготовили всё, что нужно. Давайте приступать. Я не указал, но возьмите ведро молока. Если, конечно, вы хотите избавиться от... В общем, съешьте нанитов. А теперь выпейте молока. После столь болезненной операции (что? Болезненной? Мы ж серьёзные люди — и кубизм явно то показывает. Не смешите) просто встаньте рядом с активной зарядкой. Ну, в общем, вот такая панорама (точней — её кусок) должна получиться. Как видно, слева от хотбара расположилась батарейка, которая показывает текущее состояние батареи в наните. Вообще, можно кушать более одного набора машинок нанометрических, вот только это ничего путного не даст — только сменит конфигурацию. К слову, чтобы вывести наномашинок — выпейте грог Собственно, на этом вся физическая часть закончена. Далее будем управлять через планшет. IV. Ход эксперемента. Информационная часть. Всё управление происходит через беспроводную сеть, так что планшет нужен с беспроводной сетевой картой. "Протокол" общения с наномитами предельно прост. Используется функция modem.broadcast(). При этом наниты слушают эфир на всех частотах по умолчанию. Первым куском данных ВСЕГДА является строка "nanomachines". Команда уже такая: modem.broadcast(1337, "nanomachines"). Затем идёт сама функция и аргументами, так же отделёнными частями пакета. Итого: modem.broadcast(1337, "nanomachines", "команда", "первый аргумент, строковой", 2, "прошлый аргумент — числовой", "и т. д."). Не переживайте, я ещё вернусь к этому в перечне команд. Итак, начнём наш перечень с не очень нужных игроку, но полезных команд. setResponsePort(port:Number):String,Number. ОБЯЗАТЕЛЬНАЯ КОМАНДА ПЕРЕД НАЧАЛОМ РАБОТЫ! Именно. Так как вещать на всех частотах — идея обломная, лучше поставить заданный порт. Обломная настолько, что без указания порта-канала не будут возвращаться данные! Вот так всё жестоко. Поэтому пропишите modem.broadcast(PORT, "nanomachines", "setResponsePort", PORT). Например: broadcast(1337, "nanomachines", "setResponsePort", 1337). Прописали? Можно продолжать. К слову, возвращает "port", port, собственно, где port и есть указанное значение. Бесполезная фишка, кажется. getHealth():String,Number,Number. Значит, возвращает количество здоровья (текущее и максимальное). Чтобы не отвлекаться в дальнейшем, скажу сразу, что взвращаются данные так же через модем, через тот самый указанный порт. Так что не забудьте открыть его (modem.open(PORT)) и указать получение данных через event.pull("modem_message"). Формат данных: "modem_message", "адрес сетевухи на текущем компе", "адрес наноботов", порт, расстояние, "nanomachines", возвращаемые данные.... В данной функции возвращаемые данные: "health", 15, 20, где 15 — текущее, а 20 — максимальное состояния здоровья. getPowerState():String,Number,Number. Возвращает состояние энергии в наномитах: "power", 5000, 10000, где 5000 — текущее, а 10000 — максимальное количества энергии. getHunger():String,Number,Number. Возвращает состояние шкалы голода: "hunger", 10, 20, где 10 — текущее, а 20 — максимальное показания шкалы. getAge():String,Number. Возвращает "возраст" — общее время пребывания игрока на сервере в секундах с момента первого захода на сервер: "age", 1896, где 1896 — этот самый "возраст". getName():String,String. Возвращает имя игрока, который переносит наноботов: "name", "Fingercomp", где "Fingercomp" — имя игрока. Вооооооот, теперь самое интересное. V. Ход эксперимента. Часть, в которой 18 кнопок. Тык-с, теперь основное предназначение нанитов — давать всякие эффекты! Начиная от простых частиц вокруг игрока, заканчивая смертью. Есть 18 переключателей (входов в терминологии ОС), каждый даёт свой эффект. Набор переключатель-эффект называется конфигурацией. При каждом поедании нанобота эта конфигурация обновляется рандомными значениями. Если в первый раз 9 вход убивал, то теперь он, например, хилит. И т. д. ^ Выдрано из комментариев и заменено предыдущей непонятной фигнёй. Эффектами, кстати, могут быть не только всякие regeneration, но и просто спаун частиц, а также раритетные эффекты вроде магнита, притягивающего предметы. getSafeActiveInputs():String,Number. Возвращает лимит безопасных активных входов: "safeActiveInputs", 2, где 2 — это установленное в конфиге значение. getMaxActiveInputs():String,Number. Возвращает второй лимит на количество входов всего: "maxActiveInputs", 4, где 4 — тот самый лимит. setInput(input:Number, active:Boolean). Активирует и деактивирует вход. Тут всё просто — первый аргумент является числом от 1 до 18, а второй — состояние активности (true — включить, false — выключить). getInput(inpt:Number):String,Number/String,Boolean. Возвращает состояние выбранного входа. Если неверно указать — ошибка ("input", "error"). Иначе — состояние. "input", 13, true, где 13 — номер входа, а true — состояние =) getActiveEffects():String,String. Возвращает активные эффекты. Формат: "effects", "{digSpeed}", к примеру. VI. Финал. Трагедия и выводы. Собственно, поигравшись так с нанитами, активировал 9 вход. Вот такой казус возник: Угадайте, что произошло, когда я отключил креативку?) Чего и вам желаю. Выводы: Наноботы — не плод фантазии больного ума, но полезная вещь. Наноботы — штука хорошая, но только в разумных пределах. В неразумных от них можно сдохнуть. Напоследок продемонстрирую обещанное видео от автора мода про нанитов =) И включите аннотации, там инфа полезная. Удачи :P
  48. 6 баллов
    Давненько не было автокрафтеров тут. Может, кому-то пригодится моя версия. Предназначена в первую очередь для крафта всяких часто необходимых мелочей со сложными крафтами (например, компоненты OpenComputers) из примитивных исходных ресурсов (например, процессор из слитков золота и железа, тростника и редстоуна), которые у пользователя отнимают кучу времени на поиск всех транзисторов и крафт недостающих. Рассчитана на использовании робота и двух сундуков, один из которых - основное хранилище (может быть покрупнее), а другой предназначен для резервирования компонентов при крафте. Ссылка: https://pastebin.com/1gqtWLub Необходимая конфигурация робота: Проверялась работа на компонентах (корпус, память, процессор, жёсткий диск) второго уровня. Screen, Keyboard Crafting Upgrade Inventory Upgrade и Inventory Controller Видеокарта и экран первого уровня Для дальнейших потенциальных расширений: Беспроводная карта Upgrade Container Конфигурация установки: Перед роботом - контейнер ресурсов (любой из возможных инвентарей достаточного размера) Под роботом - контейнер-буфер (можно обычный сундук) Рядом желательно поставить зарядник Возможности: Рекурсивный крафт сложных рецептов. Ресурсов расходуется, по результатам практических испытаний, ровно столько, сколько необходимо. Каталог рецептов для крафта, разбитый на страницы по 10 предметов для более удобного пролистывания на маленьком экране робота. Портативность - требуется только робот, два сундука и исходные ресурсы. Желателен также источник энергии Сообщения о том, каких конкретно исходных ресурсов не хватает для крафта (исходные ресурсы - те, для которых не найдено рецепта) Процесс крафта подробно отображается на экране, чтоб за ним было не так скучно и одиноко следить (см. недостатки) Об окончании крафта робот сообщит приветливым писком. Равно как и о неудаче. Недостатки и известные недочёты: Скорость..... Крафт занимает значительное время. Например, изготовление процессора 3го уровня из примитивных ресурсов (тростник, красный камень, алмазы, дерево для резаков, слитки золота, железа) занимает около 5 минут. Стоит отметить что количество изготавливаемых предметов не сильно влияет на время (2 процессора, скорее всего, будут делаться те же примерно 5 минут). Не умеет работать с альтернативными ресурсами. Возможно, когда-нибудь исправлю. Не умеет работать с инструментами (имеются ввиду многоразовые, как молот ИК2). Возможно, так же когда-нибудь исправлю. Не умеет работать с количествами предметов более стака, а также не гарантируется корректная работа с предметами, не складывающимися в стак. Постараюсь исправить в ближайшее время. Нет поиска по именам компонентов (то есть, либо задаёте название компонента целиком, либо задаёте крафт через каталог). Когда-нибудь поправлю Проверок на наличие контейнеров не делается, так как программа писалась "для себя" и находится в разработке. В дальнейшем будут введены. Также не везде гарантируется наличие защиты от "Количество предметов: Привет". Особенности: Шаблоны содержатся в одном файле, что облегчает переносимость, но приносит определённые неудобства всвязи с размерами файла (12 строк на предмет). Буду думать, как лучше сделать (разбить на разные файлы?). Файл имеющихся шаблонов могу выложить при необходимости (на разных сборках эти шаблоны могут отличаться) Дальнейшее развитие (no promises!): Исправление имеющихся недочётов Поддержка работы по сети (заказ компонентов, сообщение о готовности - дистанционно). Работа с более сложными инвентарями - сборщики, и т.д. Работа с машинами-обработчиками ресурсов - когда-нибудь в отдалённом будущем, скорее всего. Управление: Интерфейс текстовый. Посмотреть команды главного меню можно, нажав "Enter" (оставив поле ввода пустым).
  49. 6 баллов
    Если до версии 1.6 все использовали файл /autorun.lua и были довольны, то теперь ситуация несколько изменилась. Поэтому я опишу все варианты автозапуска программ в этой небольшой заметке. С версии OpenOS 1.6 файл autorun.lua больше не запускается на rootfs (то есть на файловой системе работающей операционной системы). Вот все пять способов, которые можно использовать для автозапуска программ. Модифицировать /init.lua. Это самый плохой и ужасный вариант из всех. Во-первых, программа будет запускаться до запуска шелла и инициализации библиотек, поэтому возможны краши системы. Во-вторых, если сделать ошибку в файле, то придётся переустанавливать этот файл, что не очень удобно. Добавить скрипт в /boot. Это не такой плохой вариант, но здесь также возможны ошибки при использовании стандартных библиотек, так как бутскрипты запускаются не в самом конце загрузки. Модифицировать /etc/profile. Это файл, каждая строка которого последовательно исполнаяется при запуске программ. Проблема в том, что при переустановке системы этот файл будет перезаписываться. Поэтому не вариант. Модифицировать /home/.shrc. Это самый оптимальный вариант. Но программа будет запускаться при каждом запуске шелла. Если прописать exit в шелле, то программа запустится ещё раз. Если для графических всяких программ это самый лучший вариант, то для одноразовых демонов, которые регистрируют листнеры на ивенты и выходят, вариант не очень хороший, так как тогда листнеры зарегистрируются дважды. Использовать систему rc. Подробно о ней рассказывал @LeshaInc: http://computercraft.ru/topic/1679-rc-chto-za-zver-takoi/ Это система, которая позволяет писать своих "демонов" — программ, исполняемых в фоне — и контролировать их из шелла с помощью команд. Графические утилиты так запускать проблематично, потому что возможны всякие артефакты отображения. Поэтому используйте варианты 4 или 5 в зависимости от программы, которую требуется запустить.
  50. 6 баллов
    Сизифов код Расскажу тебе поучительную историю, брат. Присаживайся поудобнее, да тушеными мухоморами угощайся. История, значит, такая: Был у нас на проекте игрок. Назовем его Сизифом. И лежало на нем проклятие: что ни напишет — говнокод получается. Бывало, всего две строчки напишет — и даже там говнокод выходит. И вот, старается Сизиф, шлифует свою программу. И казалось бы, совсем чуть-чуть остается. Но добавляет строчку — и опять говнокод получается. Что он только ни делал: брал примеры из статей, воровал дискеты из компьютеров других игроков, и даже как-то скачал себе рекурсивную копалку Totoro. Но стоило ему внести в этот код небольшую правку, всё в скатывалось в говнокод. И прекрасный робот-шахтер превращался в тыкву не дожидаясь полуночи. И вот однажды робот Сизифа не выдержал издевательств и сделал жалобный «бип» почти человеческим голосом. Глянул Сизиф на экран, а робот пишет ему: — Обожди писать код. Включи голову, будь программистом. Призадумался тогда Сизиф над правками кода, стал размышлять над тем, что делают разные команды и как они сочетаются между собой, и вот, не прошло и недели, как написал он свой вариант копалки. И как знать, мог бы он написать копалку даже круче Totoro и выкопать все алмазы на сервере, но неожиданно вайп случился. Удалил тогда Сизиф свой старый аккаунт, зарегистрировался под новым ником и, поговаривают, даже в вайт-лист попал, и скоро мы сможем увидеть его прекрасные программы. Хотя казалось бы, говнокодером раньше был. Историю эту я узнал из перехваченного секретного сообщения в закрытой части OpenNet, расшифровал худо-бедно, да тебе поведал. Настоящий ник игрока сообщать не буду, и так уже много лишнего рассказал. Ты же знаешь — администрация наша кровава. Но этой историей я не мог не поделиться с тобой. Радуйся, брат! Ибо в твоей голове сокрыта великая сила.
Эта таблица лидеров рассчитана в Москва/GMT+03:00
×
×
  • Создать...