swg2you
Пользователи-
Публикации
219 -
Зарегистрирован
-
Посещение
-
Победитель дней
20
Тип публикации
Блоги
Профили
Форум
Багтрекер
Магазин
Все публикации пользователя swg2you
-
Крутотень. От себя добавлю несколько скринов: Из замеченных багофич: - Перепрошивка eeprom не сохраняется после рестарта (спасает подмена файла) - при старте генерит события component_added для всех частей, чего на реальном OC не происходит - computer.shutdown(true) - не работает - os.date('!%R') - не работает - клавиша '~' - генерит событие с неправильным кодом - события clipboard, drag, drop, scroll не генерятся - редактор форумных постов кривой )
-
Думаю для параллельных вселенных движущихся относительно нас с неравномерной скоростью это норма ) Всегда можно повысить частоту опроса написав local e={computer.pullSignal(.05)}, но в этом случае не лишним будет добавить условие, и выводить время только если оно изменилось, local ot='' while true do local e={computer.pullSignal(.05)} local t=os.date('!%R') if t~=ot then prnto(1,1,t) ot=t end --... end чтобы избежать неоправданных трат драгоценной энергии.
-
Задумал я значится в своей программульке часики в углу выводить, куда ж без них. Пишу такой while true do local e={computer.pullSignal(1)} prnto(1,1,os.date('!%R')) --... end ан, нет. Часики то выводятся, но минутки иногда проскакивают через одну. Как оказалось, игровая минута вовсе не равна игровой секунде. while true do local e={computer.pullSignal(.833)} prnto(1,1,os.date('!%R')) --... end а вот так намного лучше. 1 игровые сутки == 20 реальных минут 24ч*60м=1440 игровых минут == 20м*60с=1200 реальных секунд 1200/1440=0.8(3)
-
Не зная логики сервера полагаю, что можно сделать как-то так: M=component.modem;M.open(1)M.broadcast(1,"","","getip")E=load('R={event.pull(10,"modem_message")}')U="update"E()M.send(R[3],1,U,R[6],U,"getFile","client/boot")E()load(R[8])() --и развернуто M=component.modem; M.open(1) M.broadcast(1,"","","getip") E=load('R={event.pull(10,"modem_message")}') U="update" E() M.send(R[3],1,U,R[6],U,"getFile","client/boot") E() load(R[8])() В смысле грузить код из "boot" а в нем уже творить все остальное. ЗЫ Интерфейс консоли сервера зачотный _/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/ _/_/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/_/_/_/ _/_/ _/ _/ _/_/_/_/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/ _/_/_/ _/ _/ _/ _/ _/ _/_/_/_/_/ _/ _/ _/ _/ _/ _/ _/ _/_/_/ _/_/_/_/ _/ _/ _/ _/ _/_/ _/_/_/ _/_/_/_/ _/ _/ _/ _/ _/_/_/_/_/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ рулит
- 162 ответа
-
- 1
-
-
- OpenComputers
- OpenNet
-
(и ещё 1 )
Теги:
-
Ва-а! Я даже не думал что так ({}) можно обратиться к элементу таблицы. В своем, я перенес метку в другое место, что сэкономило один байт на разделителе, и выбросил pcall. --код 90 байт: --C=component::R::C.proxy(C.list('od')()).open(7)E={computer.pullSignal()}load(E[6])()goto R --он же развернутый: C=component ::R:: C.proxy(C.list('od')()).open(7) E={computer.pullSignal()} load(E[6])() goto R Если применить твой метод обращения к элементу таблицы, то можно сократить до 89 байт, но такие сокращения годятся только для разминки мозга, на практике этот код нестабилен, любое "неправильное" событие приведет к ошибке. >Обрати внимание как я проверяю название сигнала: _=a:find"mo"and m.send() красота в чистом виде, такие конструкции меня всегда приводят в восторг >если инициализировать контроллер\дрон первым сообщением Выбросить цикл и не проверять "правильность" события можно, но я пошел по другому пути. === Код для EEPROM в 94 байта полностью сохраняющий функционал: --код 94 байта: C=component::R::C.proxy(C.list('od')()).open(7)E={computer.pullSignal()}load(E[9]or'')()goto R --он же в развернутом виде, с комментариями: C=component ::R:: --метка в этом месте экономит 1 байт, т.к. служит одновременно разделителем соседних участков C.proxy(C.list('od')()).open(7) --а то что мы будем открывать уже открытый порт - не является исключением и вполне допустимо E={computer.pullSignal()} --параметры события будем сохранять поскольку мы будем их использовать в загружаемом коде load(E[9]or'')() --Если у нас возникло событие вернувшее 9-й параметр, то это наше событие, иначе выполняем пустоту '' --Стандартные события возвращают не больше 6-ти параметров, а если говорить о сетевых, то --маловероятно, что кто-то будет делать broadcast с таким количеством параметров. --broadcast(port, mess1, mess2, mess3, mess4) <--такое маловероятно, но если встретится, --то ничто нам не помешает, пожертвовав одним байтом сдвинуть позицию еще дальше. --Поэтому "правильность" события будем кодировать позиционным методом. goto R Теперь у нас есть сверх-компактный код хранимый в EEPROM, и нам осталось обеспечить обработку ошибочных ситуаций. Поскольку даже самая простая планка ОЗУ имеет в 48 раз больший объем чем EEPROM (192к против 4к), то вполне логичным шагом будет перенос обработки исключений в оперативную память. Напишем конверт обеспечивающий безопасную компиляцию/выполнение кода пользователя и возврат результата или сообщения об ошибке: U = table.unpack R = {load(E[10])} --10-й параметр события загружаем как код пользователя --конечно, можно заключать код пользователя в конверт простой конкатенцией строк, но такая методика --порождает "проблему кавычек" и может приводить к ошибкам, поэтому конверт отдельно, код отдельно if R[1] then R = { pcall( R[1], U(E, 11) ) } -- end --если компиляция успешна пробуем выполнить чанк передав ему все оставшиеся параметры C.proxy(C.list('od')()).send(E[3], 7, U(R)) --и возвращаем отправителю результаты или ошибку если при компиляции/выполнении возникли проблемы Теперь свернем код конверта, напишем функцию выполняющую код пользователя на удаленных устройствах, и попробуем с ней поиграть. Длиннокод с длиннокомментариями: local wrap="U=table.unpack;R={load(E[10])}if R[1]then;R={pcall(R[1],U(E,11))}end;C.proxy(C.list('od')()).send(E[3],7,U(R))" --конверт объявляем снаружи, мало ли где еще пригодится function enetRun(addr, code, ...) local result=false if type(code)=='string' then --load() в eeprom должен получать только строки if addr then --приемник должен генерировать событие вида --E=={'modem_message', rAddr, sAddr, port, dist, nil, nil, nil, wrap, code, ...} -- ^1 2 3 4 5 6 7 8 9 10 11 --поэтому посылаем конверт, код и параметры начиная с 9-й позиции события result=modem.send(addr, 7, nil, nil, nil, wrap, code, ...) -- ^6 7 8 9 10 11 else --если адрес получателя не задан, то отправляем всем желающим result=modem.broadcast(7, nil, nil, nil, wrap, code, ...) end end --и возвращаем true если получилось отправить return result end --теперь попробуем что-то поотправлять: enetRun(nil, 123) --это не пропустит наша функция enetRun(nil, 'computer.beep(440)') --это просто выполнится в удаленном устройстве, пискнет там нотой Ля и вернет: true --теперь мы сможем организовывать концерты контроллеров и дронов с солистом роботом enetRun(nil, 'return 123+...', 4) --это выполнится и вернет нам: true, 127 enetRun(nil, 'q') --это отправится, но наш конверт вернет нам: nil, "и текст ошибки компиляции" enetRun(nil, 'q()') --это тоже отправится, но конверт вернет нам: false, "текст ошибки выполнения" --теперь мы можем удаленно выполнять свои хелловорлды enetRun(nil, 'return "Hello world"') --передавая им строковые, числовые, nil-ы или булевы параметры enetRun(nil, 'return ...', 'Hi', nil, true) --но даже не пытайтесь передать больше 3-х параметров: --enetRun(nil, 'return ...', 1, 2, 3, 4) - на это modem.send будет ругаться: false packet has too many parts --мы ведь передаем 3 nil-а, конверт и код, это уже 5, а modem.send, по видимому, умеет не больше восьми --также не пытайтесь передавать другие типы данных: таблицы, потоки, и т.п. --enetRun(nil, 'return ...', {}) - modem.send обругает вас: false unsupported data type --возврат "неправильных" данных вызывающий ошибку на стороне удаленного устройства оставим на совести пользователей --enetRun(nil, 'return {}') - треш, краш и халт в modem.send удаленного устройства --но, если очень захочется, то send конверта можно заключить в pcall, чтобы красиво обработать и это исключение --осталось получить все что нам прислали наши контродроботы repeat local e={computer.pullSignal()}; e[2]=tostring(e[2]):sub(1,3) --обрезав адреса до 3-х символов e[3]=tostring(e[3]):sub(1,3) prn(table.unpack(e)) until e[1]=='key_up' --и выйти по аникею пропищав напоследок Си computer.beep(329.6) --напомню, что enetRun(addr, '') будет обращаться к конкретному устройству --а enetRun(nil, '') позволить опросить все доступные, чтобы выбрать любимчика --ах, да, prn() это моя собственная функция вывода, у меня нет OpenOS, пишите там print --и не забывайте вначале получить экземпляр модема и открыть 7-й порт, чтобы видеть ответы На этом пока всё, спасибо всем отписавшимся, и отдельное спасибо Krutoy за повышение планки и наталкивание на идеи. ЗЫ Интуиция подводит. С Lua я играю всего пару недель и исключительно через СС OC, хотя кодер довольно опытный, однопроходные дизассемблеры для зилоговских процессоров еще в начале 90-х писал. Потом были бейсики с паскалями, потом LD, FBD, SFC и паскалеподобный ST в разных скадах и плк. Потом кодить бросил и переквалифицировался, а сейчас вот увлекся и трясу стариной, чтоб мозги не сильно ржавели.
-
goto --> http://www.lua.org/manual/5.2/manual.html#3.3.4 Применение бесконечного цикла на goto позволяет сэкономить 5-6 байт, сравните длины: ::L::a={}goto L while a={}true do end repeat a={}until nil Тем кому религия не позволяет пользоваться goto, хочу напомнить, что абсолютно все виды циклов, в конечном итоге, строятся на основе переходов. --- Размер не важен, если кроме этого кода в EEPROM больше ничего не нужно. Но если вы будете писать, к примеру, дрона с серьезной логикой, или операционную систему работающую из чипа, или интеллектуальный загрузчик с встроенным файловым менеджером, просмотром окружения и доступных устройств, то в 4к вам будет тесновато, и блок, добавляющий возможность выполнения присланного по сети кода, удаленной перепрошивки и прочего - должен быть как можно меньше. На самом деле, это просто получение удовольствие от стремления к идеалу. Спортивный интерес, если угодно. --- >без изменения функционала удалось сжать его всего на 4-10 символов. >Если отказаться от отсылки сообщений об ошибках обратно, которые можно и так определить первым сообщением, код получается 92 байта Моя хотеть созерцать эту красоту. upd: Хотя нет! Моя хотеть достичь этой красоты самостоятельно. upd2: Нет предела совершенству. Если поставить задачу: в бесконечном цикле, не проверяя на сигнал модема, не обрабатывая ошибок, выполнять полученный по сети код то можно уместиться в 90 байт.
-
>Вот это - явно какое то шаманство и запрещенные техники. Я такого еще никогда за 2 года программирования на Lua не видел. Не разочаровывай меня, это же основы языка. >А по теме - для биосов что только не делали. Даже превращали его в жесткий диск, переписывая прямо исходник биоса. Твоя программа полезная, но не новая. На новизну никто и не претендует, выполнить код полученный по сети не велика задача, здесь главное форма реализации, ну а код по ссылке - очень плохой пример. Мой код умеет так же, но он намного более компактный, стабильный и функциональный. >Кстати, твой код всё еще можно уменьшить не изменив функционал. А вот здесь поподробней пожалуйста.
-
Привет all. (после публикации заметил ошибку в названии темы и тегах, код для OpenComputers а не для ComputerCraft, я их постоянно путаю) код 204 байта: _=component;m=_.proxy(_.list('modem')())m.open(7)u=table.unpack::r::e={computer.pullSignal()}if e[1]=='modem_message'then;_={load(e[6])}if _[1]then;_={pcall(_[1],u(e,7))}end;m.send(e[3],7,u(_));end;goto r или код 231 байт: ::r::pcall(load("_=component;m=_.proxy(_.list('modem')())m.open(7)u=table.unpack::r::e={computer.pullSignal()}if e[1]=='modem_message'then;_={load(e[6])}if _[1]then;_={pcall(_[1],u(e,7))}end;m.send(e[3],7,u(_));end;goto r"));goto r Записать в EEPROM любого устройства имеющего сетевую карту, и включить устройство. На отдельном компьютере выполняющем роль сервера выполнить код примера: modem.open(7) modem.broadcast(7, "return 'Hello ', _VERSION, ...", true, 42, 'bebebe') Прочитать ответ от модема, и понять что произошло. ============================================= Дополнительные примеры: broadcast(7, 'bebebe') broadcast(7, 'bebebe()') broadcast(7, 'return {}') broadcast(7, true) broadcast(7) broadcast(7, 'return computer.pullSignal()' ) code=[[ --my super puper long program nice code ]]; broadcast(7, сode) broadcast(7, 'component.proxy(component.list("eeprom")()).set(...)', codeforflashing) и прочие извращения 1,2 покажут обработку ошибок на стадии компиляции и выполнения; 3,4,5 покажут различие в коде 204 и 231 и ограничения передачи данных; 6,... - некоторые возможности Для самых бегемотов: Можно Хранить код 204 в setData Можно добавить аутентиикацию, чтоб вражина за стенкой не broadcast-ил нам тут с планшета Можно построить SCADA-систему из дронов, роботов, контроллеров и компьютеров. Что-то еще... ЗЫ mods/OpenComputers-MC1.7.10-1.5.12.26-universal.jar примеры не проверял, писал здесь сходу.
-
Код — это поэзия! Я думал реализовать что-то подобное в отдельной утилите. Убирать форматирование/комментарии, заменять имена переменных/функций на короткие (при включении сжатия с потерями), заменять повторяющиеся части ссылками на словарь и сохранять результат упаковки в файл вместе с кодом распаковки. Этакий UPX для Lua. Любопытный код. Спасибо за ссылку.
-
load (ld [, source [, mode [, env]]]) это стандартная функция Lua, которая берет переданную ей текстовую строчку с кодом, и если в нем нет ошибок - возвращает скомпилированный чанк в виде функции содержащей этот код. Т.е. код local f = load('return a, b') эквивалентен объявлению local function f() return a, b end за тем исключением, что функция созданная с помощью load получает свое собственное локальное окружение и перестает видеть локальные переменные a и b объявленные в основном коде.
-
Loadfile не поможет. Мой код выполняется из eeprom когда loadfile еще не существует. Я сегодня пол дня потратил на исследования и поиски решения ) Да увлекся lua и играю с кодом. Пишу пока непонятно что, и в этом непонятно чём есть обработка событий от клавиатуры. Но код вида: local e = {computer.pullSignal()} if e[1] == 'key_down' then if e[4] == 28 then cls(); t=t["os"] elseif e[4] == 208 then cy=cy+1 elseif e[4] == 200 then cy=cy-1 elseif e[4] == 41 then computer.shutdown(true) end end громоздкий и некрасивый, на мой взгляд. Lua позволяет сделать это красивее и компактней, поэтому обработчик был переписан: local k = { [41] = function () computer.shutdown(true) end; [208] = function () cy=cy+1 end; [200] = function () cy=cy-1 end; [28] = function () cls(); t=t["os"] end; } local e = {computer.pullSignal()} if e[1] == 'key_down' and k[e[4]] then k[e[4]]() end который мне тоже не понравился своей избыточностью. Ладно если у нас 3-4 кнопочки должны обрабатываться, а если больше? Для каждой кнопочки писать "function ()" и "end" - непозволительная трата байтов. Поэтому код был переписан так: local k = { [41] = 'computer.shutdown(true)'; [208] = 'cy=cy+1'; [200] = 'cy=cy-1'; [28] = 'cls(); t=t["os"]'; } for i,s in pairs(k) do k[i]=load(s) end local e = {computer.pullSignal()} if e[1] == 'key_down' and k[e[4]] then k[e[4]]() end что экономило бы по десятку байт на каждую следующую кнопочку. Но тут я столкнулся с проблемой. Чанки загруженные с помощью load(s) теряли связь с локальным окружением.
-
Печально. Отличный инструмент оказался неработоспособным. Спасибо за содержательный ответ.
-
И что это даст? Конкретная задача.
-
q all есть следующий код: a = 1; local b = 2 local f = load('return a, b') print(f()) который дает вывод: 1 nil а нужно: 1 2 как сделать, чтобы функция f видела локальную переменную b ? upd: это в OpenComputers, т.е. Lua 5.2 upd2: теоретически нужно при загрузке чанка указать окружение, что-то вроде: local f = load('return a, b', '', 't', _ENV) но трабла в том, что _ENV это ни разу не локальное окружение. print(_ENV==_G) дает true
