Пожертвовать на дальнейшее развитие:
Рубли: R849464451336
Гривны: U145931779718
Доллары: Z353114408274
410011422550405
--v.2.40--
Вынес на форму настроек окошко для задания размера файла логов.
Добавил переменные, в которых содержится путь к текущему скрипту 'scriptPath' и имя скпирта 'scriptName'.
Добавил почти все переменные Ultima Online в Lua. Указывать со скобками, как функции.
http://uopilot.uokit.com/index_rus.php
http://uopilot.uokit.com/old/dl240.php
http://uopilot.uokit.com/dllua.php
http://uopilot.uokit.com/dlAntiFrost.php
http://uopilot.uokit.com/dlAntiGate.php
пароль на архивы: uopilot.uokit.com
Findimage при поиске на скрине не доделан?
С 12й бетки (или 11, у меня её нет) не работает 2й тип поиска. Не находит картинки.
build 1
Добавил длл "lua5.1.dll" в ресурсы пилота. При запуске пилота проверяется ее наличие в папке, и если ее нет, то распаковываем.
В клики мышкой добавил параметр "nooffset", который позволяет игнорировать смещение, указанное в переменных "clickoffsetxy". 'kleft 100 100 nooffset'
build 2
Исправил вывод сообщения об ошибке при форматировании скрипта, если пилот располагался поверх всех окон.
Исправил тип поиска 2 в 'findimage', сломанный пару билдов назад.
Добавь в первый пост ссылку на свою страницу. Не все же знают где она и где искать бетки.
set Clickoffsetx 50
set Clickoffsety 50
move 0 0 // смещения нет
wait 100
log mousepos_x mousepos_y
move 0 0 nooffset // смещение есть
wait 100
log mousepos_x mousepos_y
end_script
Работал себе в версии 2.32, подумал пора переходить на новую. Через час мучений вернулся обратно.
left #xx, #yy ~
sendex ~ // зажать шифт
wait 30 // возможно без паузы будет работать
left 100 100 // клик в координаты 100 100
wait 30 // возможно без паузы будет работать
sendex // отпустить шифт
end_script
build 3
Исправил клики мышкой с модификаторами.
Надеюсь колесики не отвалились.
Error while creating Lua virtual mashine. При запуске любого скрипта.
Скачал lua5.1.dll положил в папку пилота. Что не так?
Удалить lua5.1.dll. Скачать бета версию пилота: http://uopilot.uokit.com/dlnight.php
Есть какой-нибудь пилот, чтобы x-trap не блочил его? Обычно работал, а щас перестал...Либо сам пилот вылетает, либо игра при привязке к игре.
set windowpos 100 100
End_script
set windowpos 100 100 workwindow
End_script
build 4
Исправил работу команды 'set windowpos', если не указан хендл рабочего окна.
wheel_up 597 263 2
wheel_up - (27): Ошибка! Проверьте правильность скрипта! EConvertError '' is not a valid integer value
wheel_up 597 263 2
Чо за переменные для Ultima и работают ли они для других игр??? просто я нуб и не понимаю для чего они нужны.
А чо еще нового в версии 2.40. В чем отличия от 2.39 хотелось бы узнать более полный список правок и нововведений.
Color бы переделать под способ забора изображения из findcolor. Как вариант сделать два опреатора, т.к. они дают зачастую разные координаты. Дело в том, что в связи с какими-то просто шедевральными изменениями findcolor больше не садит fps вообще. Сейчас приходится финдколор оборачивать в пользовательскую функцию либо использовать его напрямую (ну или по-стринке садим fps).
Так же выдает ошибку: set - Error while creating Lua virtual mashine при работе с findimage, if, while да и прочих командах. Проблема возникла в свежо-скачанной версии пилота 2.40.
Пробовал скачать lua5.1.dll в папку с пилотом - не помогло.
Как лечить болячку?
...
В UOpilot 2.40 b004 вроде фурычит
На новой версии при запуске любого скрипта появляется ошибка:
"Error while creating lua virtual machine"
Длл и для 5.1 и просто луа.длл в папке есть(я даже в систем32 их скопировал.)
Так же перестал работать поиск картинки почему-то.
Запускаю один и тот же скрипт на 238 версии и на 240, 38-я всё находит, 40-я пишет что картинка не найдена.(потыкался с разными параметрами и картинками, вообще ни при каких условиях не ищет. Причём функция ошибок не возвращает - просто 0, тоесть картинок не найдено.
Винда 7-я pro со всеми обновлениями.
Вот код скрипта на котором я тестил если вдруг поможет:
set #Result FindImage (0 0 800 800 (C:\Users\Владимир\Desktop\автокликер\images\test.bmp) %ResultArray 2 50 1 10)
if #Result > 0
msg Изображение найдено в координатах X= %ResultArray[1 1] Y= %ResultArray[1 2].
else
msg Изображение не найдено
msg ошибка #Result
end_if
wait 10s
http://uopilot.uokit.com/index_rus.php
"Ночная" версия
Стабильная
12.12.2017 Build 004
В ней исправлены баги.
В новой версии продолжает появляться ошибка с луа. Однако поиск по картинке у меня начал работать нормально.
в последней версии не работает wheel_up и wheel_down.
При попытке использования высегда выдает ошибку EConvertError " is not valid integer value.
Даже на коде:
set #x 420
set #y 350
wheel_down #x #y abs 3
wait 10s
Пилот по прежнему косячит .ini ну или может что то еще сами судите..
Так вот.. в процессе разработки я периодически добавлял и убирал листы. Закрываю на крестик, автосейв при закрытии включен. Перезапускаю пилот - всё на своих местах, как должно быть. Привязываю окна к л2 запускую, и всё ок - играю... жму хоткеи для запуска скрипта 3, 4 и 6 и тут, на тебе ошибка в лог,
один хоткей не может быть назначен двум скриптам одновременно . Смотрю скрипт 3 теперь не БД, а свс, жму открыть выбираю скрипт бд для 3 листа, всё опять на местах. Запуск - всё ок. проходит время, БАЦ! свс творит что-то не то, теперь лист 4 с свс внезапно стал c ЕЕ скриптом. Опять жму открыть - выбираю нужный скипт опять всё ок и работает как надо.
Проходит время и опять эта мешанина происходит с одним из листов 3,4 или 6, прям на ходу, ужасно бесит..
Удалить .ini и по новой настроить помогает.
Но стоит мне что-нибудь переделать приходится удалять .ini и настраивать по новой.
Надеюсь в новой версии проблему удастся устранить
Выкладываю архив с пилотом в котором этот баг регулярно выстреливает.
https://drive.google.com/open?id=1BWd5YqHmr4eg1tF97euIPEcxjILl9Zid
Кстати мой скрипт весьма крут и думаю будет востребован в мире л2, только там есть ошибка которую я не могу найти. Иногда.. оч редко.. хиллер промахивается по таргету и хилит не того. Если кто поймет в чём дело можно будет выложить в готовые скипты, а я буду благодарен.
А теперь немного вкусностей из ночной кухни
Вышла новая ночная сборка хоть и из нестабильной ветки, но весьма достойная внимания.
Теперь мы полностью избавились от проклятого Crystal Lua с его багами и фантазиями разработчика.
В связи с чем полноценно заработал require.Теперь не будет проблем с подключением сторонних плагинов и расширений.
Так же мы перешли с чистого Lua, на LuaJIT. Что это такое и чем нам грозит? Переписывать скрипты не придется. Они полностью совместимы. Разница в динамической компиляции, благодаря которой LuaJIT показывает очень существенный прирост в производительности.
Так же несколько приятных плюшек:
Wknight сделал нажатие по коду клавиши в командах 'send*' и 'sendex*'. Коды указывается в качестве параметров в фигурных скобках. При указании нескольких клавиш, пробелы между скобками обязательны. "send {49} {112}"
В старом синтаксисе исправлен 'return' в 'for' и 'repeat' из двойного 'gosub'.
Поскольку работа кипит и сборка из нестабильной ветки есть и некоторые огрехи:
переменные пилота в луа пока не передаются.
Прикрепленные файлы
uopilot_d_11.03.2018_Build_004.zip ( 1,68 мегабайт )
Кол-во скачиваний: 212
Это конечно все здорово, но зачем новые фичи идут и в старый синтаксис ? Можно развернутый ответ ? Очень озадачен.
Скрипт даже не желает запускаться. Без ошибок. 0 реакции.
--build 5--
Расширил до 16к строку параметров передаваемую в команду 'prompt'.
Исправил открытие формы параметров персонажа за пределами экрана, при наличии нескольких мониторов.
Сделал автоматическое определение ширины окна команды 'prompt'.
Заменил "Lua 5.1" на "LuaJIT 2.0.5". Убрал сторонний компонент для связи с луа.
Сделал нажатие по коду клавиши в командах 'send*' и 'sendex*'. Коды указывается в качестве параметров в фигурных скобках. При указании нескольких клавиш, пробелы между скобками обязательны. "send {49} {112}".
Исправил 'return' в 'for' и 'repeat' из двойного 'gosub'.
Добавил вывод ошибки запуска скрипта Lua и несколько строк кода вокруг указанной.
Все переменные пилота, которые были доступны из Lua (17 штук), в Lua теперь функции. Те, которые доступны для изменения (9 штук), в качестве параметра принимают новое значение, возвращают старое (включая 'workwindow()').
Починил галочку "Отображать оставшееся время ожидания".
При приостановке скрипта, текущая команда типа 'wait' прерывается.
Во время задержек в скрипте, таймер на панели параметров персонажа продолжает обновляться.
Добавил еще несколько параметров в команду 'hint (fontSize fontColor posX posY width height backColor fontStyle fontName (any text))'. Где
'backColor' - цвет фона;
'fontStyle' - "n" - normal, или комбинация следующих: "b" = bold, "i" = italic, "u" = underline, "s" = strikeout;
'fontName' - имя шрифта установленного в системе.
Добавил в меню по ПКМ того, чего там небыло.
Возвращаемое значение функции 'color' изменено на целочисленное.
Возвращаемое значение функции 'readmem' зависит от типа читаемого значения.
--build 6--
Исправил сломанные команды прокрутки колеса мыши.
hint 111
--lua
while 1 do
wait (100)
end
Малевича разукрасил.
Ошибка 100 не воспроизводится.
--lua
while 1 == 1 do
local lastX = mousepos_x()
local lastY = mousepos_y
wait (100)
end
Кнайт, а у тебя случаем пилот не перекрывает окна ошибок? А то я тоже не всегда их замечаю и не могу понять в чем дело) Вытащить бы их на поверхность, когда пилот поверх всех окон.
build 8
Убрал сообщение "runtime error", вызванное прерыванием Lua скрипта.
Ты его подавил или lua код теперь тоже прерывается нормально?
Отфильтровал. Но эти две вещи не связаны. Как прервать чистый луа - пока вопрос открытый.
всегда можно прибить нитку с машиной)
Проблемы с подключением файлов через require:
--lua
local serpent = require"serpent"
--log(serpent)
end_script()
build 9
Добавил переключение закладок скриптов по Ctrl+Tab, Ctrl+Shift+Tab.
Сделал функцию 'mouse_pos (["abs"])' в Lua. Возвращает два числа - x,y.
В нестабильной ночнушке от 06.05.2018 Build 009
Сделал принудительное закрытие VM Lua, при остановке скрипта.
Это соседние скрипты не рушит?
Не проверял, но не должно, вм перезапускалась и раньше, сейчас просто принудительно прибивается. Мне это не особо нравится, но иного способа прервать скрипт на чистом Луа, я пока не нашел.
build 10
Сделал принудительное закрытие VM Lua, при остановке скрипта.
Исправил функции 'findcolor', 'findimage' в Lua.
Добавил возврат "nil" и "LuaTable", как было в предыдущей версии Lua.
Хз можно ли снаружи принудительно в скрипте включить дебаг и пуш функции, но если это можно сделать, то включаем дебаг, включаем выполнение фукнции после каждого перехода строки, функцию делаем специально с ошибкой, чтобы скрипт выбило. Вывод ошибки подавляем. В луа нет встроенной функции выхода даже из самого кода. Предполагается, что выполнение закончится либо в конце скрипта либо через return снаружи функций. Беглый поиск ничего умного не дал, но этот костыль хотя бы относительно безопсный.
В версии 2.40d b010 от 19.05 криво работают следующие функции:
set Clickoffsetx
set Clickoffsety
Для команд Kleft и Kright они работают хорошо, но вот на команду Move влиять перестали
set Clickoffsetx 50
set Clickoffsety 30
move 100 200 nooffset // должно работать наоборот, т. е. игнорировать Clickoffset
wait 100
msg Координаты курсора: mouseposabs_x mouseposabs_y
end_script
set Clickoffsetx 50
set Clickoffsety 30
move 100 200 nooffset // должно работать наоборот, т. е. игнорировать Clickoffset
wait 100
msg Координаты курсора: mouseposabs_x mouseposabs_y
end_script
Сегодняшняя нестабильная ночнушка.
Зачем save_array добавляет табуляцию в конец строки? Она нужна вообще?
Может быть убрана. Просто когда пишешь сохранение, то так получается само по себе заачастую. В противном случае первый/последний виток цикла обрабатывать приходится индивидуально. Точно так же ты можешь наблюдать пустую строку в конце герерированных файлов (не только про пилот).
Оно мешает?
build 11
При вставке в скрипт Lua из меню по пкм, к именам функций добавляются круглые скобки.
При выводе сообщений в лог, символ '\n' дополняется до '\r\n'.
Исправил 'clickoffsetx' и 'clickoffsety' в комамнде 'move'.
В Lua добавил функцию 'get_script_text (номер_скрипта)'. Возвращает в таблицу скрипт с указанным номером, либо текущий, если номер не указан.
Убрал все преобразования строки, выводимой в лог из Lua. Оставил только дополнение '\n' до '\r\n'.
Исправил утечку памяти, появившуюся при смене Lua.
Библиотека Lua загружается и инициализируется только при запуске скрипта на Lua.
--lua
log (123)
--lua
local s="save"
log(s)
Я вот сейчас стал искать новую версию, нашел 2.40. Вижу, что опубликована была давно, а её у меня нет, хотя всегда, когдая пишу скрипт, то проверяю новую версию. Полагаю, что я её по какой-то причине удалил, которая делала скрипт неработоспособным.
Примерно полтора года назад столкнулся с ситуацией:
https://forum.uokit.com/index.php?showtopic=29951
У меня не получилось перехитрить игру. Делал через оконный. Если у кого-то есть спортивный интерес, то игра Sinister City в Steam. Вдруг кто-то решит заморочиться.
Ушел искать бету. Погоняю через неё актуальные скприты. Может чего сообщу. Надеюсь, что Винду не уронит.
if #timeNextBuff1 < timer // Первый блок
send {F1}
wait 2000
set #timeNextBuff1 timer + 120000 // Указываем через сколько времени повторить действие в миллисекундах (1000 = 1 cек).
end_if
Итак, поставил последнюю версию.
Мои пожелания:
- меню, где выпадающие списки "скрипт, макрос, настройки, справка", нужно сделать ограничение по минимальной ширине, чтобы не было 2-х строк.
- внизу, кнопки управления, как видно, находятся внутри какого-то блока. Я сопоставил размеры кнопок внутри и блока. Увеличить кнопки в высоту, за счет уменьшения отступов, или даже с полным наложением упростило бы попадание по кнопкам.
- вкладки: при активации на вкладку она как бы проваливается, при этом повляются границы dotted. Эти границы мешают. Для выделения достаточно затемнять неактивные.
- так как элементы маленькие, особенно квадратики зеленые и красный (старт/стоп), то было бы круто для них сделать что-то вроде помощи в прицеливании.
- см. баг 1. Если кто-то всё же будет настолько упорот, что ему нужно будет там 10-тизначное число, то следует обозначить, что у этого наркомана за границами ещё цирфы. Хорошим решением будет вывод значения в подсказке при наведении. "100 миллисекунд - пауза между строками".
Баги:
- в паузу между строками можно писать значение, начинающееся с ноля. Можно вписать 30-тизначное число и получить "Неправильно указана задержка между строк". Кому нужно 30-тизначное число? Ещё можно писать туда буквы и дроби (не варит, да и не надо). Решение: input'у позволить принимать только цифры типа int с каким-то максимальным кол-вом символов.
- prompt (подсказка) вызвала окно, где кнопка OK частично перекрывает input. С окна с несколькими вариантами вообще "ОК" можно убрать, так как нажатие по варианту и так срабатывает, как подтверждение с закрытием окна.
Интерфейс случаем не через Windows Forms делается?
Вопросы:
- внизу окна, сразу на вкладками прямоугольник с черными линиями во всю ширину окна. У него есть практическое назначение?
- чуть выше справа указатель строки, где находится курсор. Он перекрывает ползунок. Я думаю, что его можно опустить под вышеописанный прямоугольник, тем самым предоставив ему больше места, сейчас на минимальной ширине там нужно 10 вкладок.
Подтверждение исправления:
- b011 при первом запуске распаковал lua5.1.dll и libgcc_s_dw2-1.dll
- log window показывает о сочетании клавиш для остановки всех скриптов
Понравилось:
- группировка по вкладкам в меню "Настройки"
Эскизы прикрепленных изображений
UOPilot повесился. На вкладке был скрипт, которые не выполнялся. Была выделена одна буква (первая) у строки wait 500. Были выбраны #handle и имя окна через ctrl+A, которые принадлежали уже закрытой программе. Тыкнув на что-то из них, кнопку 'log' или checkbox справа, пилот повесился.
build 12
Добавил функцию получения приоритета процесса 'GetProcessPriority ([handle|PID])'. Если хендл не указан, возвращает приоритет пилота. Возвращаемые значения: '-3' - Error; '-2' - Idle priority; '-1' - Below normal priority; '0' - Normal priority; '1' - Above normal priority; '2' - High priority; '3' - Realtime priority;
Добавил функцию установки приоритета процесса 'SetProcessPriority ([[handle|PID] priority=0])'. В случае успеха возвращает "0", иначе код ошибки. Если хендл не указан, устанавливает приоритет пилота. В качестве 'priority' используются теже значения, что возвращает 'GetProcessPriority'.
В тестовом режиме добавил функцию установки маски ядер процессора для указанного процесса 'SetProcessAffinityMask ([[handle|PID] mask=0])'. В случае успеха возвращает "0", иначе код ошибки. Если хендл не указан, устанавливает приоритет пилота. В качестве 'mask' указывается "0" - все ядра, либо сумма следующих значений: 1 = CPU 0; 2 = CPU 1; 4 = CPU 2; 8 = CPU 3; итд...
--lua
local s="save"
log(s)
build 13
Исправил ошибку вывода первого сообщения из скрипта Lua, при ниразу не открывавшемся логе.
Добавил вывод сообщения об ошибке, при ексепшене в скрипте Lua.
:start
set %a getimage (1 1 1920 1080 workwindow)
deleteimage (%a[1 1])
wait 10
goto start
Память утекает мгновенно. Вообще из этой радости можно сделать очень неплохой просмотр перекрытых окон =)
deleteimage функция. Не заметил утечек.
Забавно. Ну функция, ну не нужно мне возвращать результат. И?
deleteimage (%a[1 1]) - утечка
set #e deleteimage (%a[1 1]) - нет утечки
Если оно функция, то оно всегда возвращает, и то, что оно возвращает надо забирать. Если оно команда, то оно ничего не возвращает, и соответственно забрать ты у него ничего не можешь. Это абсолютно разные обработчики. Включи галочку "останавливать скрипт на неопознанной команде" и ты сразу найдешь ошибку.
Можно кстати подумать на тему как всё сделать функциями с необязательной обработкой возвращаемого значения, но это в будущем, а пока так.
В луа и так всё функциями, даже вот такое работает
log(wait (2000))
random() - возвращает строку, а не число.
Каждый раз после остановки скрипта луа всплывающее окошко "Операция проведена успешно". Почувствовал себя хирургом-рекордсменом =)
Что есть фикс финдимиджа? Можно какое-то более детальное описание? Что-то менялось по синтаксису?
Рандом починил. Сегодняшняя нестабильная ночнушка.
Сообщения такого что-то не обнаружил.
Фикс десятого билда? Возвращали в луа неверное количество параметров.
Каков сейчас полный синтаксис финдов в lua? Массив на свое место перекочевал? Перед знаком равно всмысле.
Параметры НЕ стрингом и без конвертаций скртых, а нормально можно передать в финды?
Нумерация строк в луа начинается с 1. Можно привести в соответсвие редактор?
Так же был обнаружен странный плавающий баг с require.Он переодически перестает находить скрипты. Адреса при этом вроде не съезжают... Воспроизведения добиться не получается. Лечится перезапуском пилота.
Возники проблемы с dir в старом lua скрипте. Что изменено? Убрана ли конвертация? Из-за нее ранее были проблемы со слипанием макски и флага рекурсии в один параметр.
После сохранения скритпа dircreate начинает работать относительно скрипта, так же при этом require в луа теряет подключаемые скрипты. Лечится перезапуском. Подозреваю, что меняется рабочая директория.
windowpos, который есть get и set, у нас остался в луа только get.
filerename требует двойного экранирования кавычками при использовании в луа, если имена содержат пробелы. Т.е. сначала мы берем в кавычки строку, т.к. это строка и строки в луа передаются в кавычках, потом нужны еще одни кавычки, т.к. при получении пилотом параметров кавычки не передаются, а лишь служат признаком строки. Короче говоря опять идет конвертация параметров туда-сюда и из-за этого нужны доп экраны. Подозреваю, что это будет со всеми операторами работы с файлами.
SetProcessPriority, GetProcessPriority, SetProcessAffinityMask - в луа не существуют.
При эмуляции через:
--lua
set ("SetProcessPriority(" .. handle .. ", 3")
Приоритет почему-то был выставлен высокий, а не реал тайм.
Вообще очень полезная фишка. Зачастую приложение подлагивает и его лучше всего повесить на одно ядро с пилотом, пилоту дать низкий, приложению реалтайм. Вероятность пролагиваний нажатий после этого сильно уменьшается. В одном особо тормозном приложении без адекватной возможности контроля ввода данных получилось добиться полной стабильности работы без каких-либо вейтов при том, что ввод первой ячейки в таблице происходил мгновенно, на тысячной ячейке уже занимало секунд 10. При таком ужасе абсолютно не нужен был контроль корректности - просто спамил пилотом, приоритеты сами все сделали.
--lua
setprocesspriority(workwindow() , 3)
lua чувствителен к регистру, поэтому все функции зарегистрированы только маленькими буквами.
Чем больше вариантов, тем дольше работает парсер.
Так параметры у финдов вроде давно из луа нормально задаются, без преобразования в строку. Или где-то проскакивает старый вариант?
Как то так
aa, c = findimage(10, 20, 1020, 810, {"C:\\tmp\\image.bmp"}, 2)
Странно, я был уверен, что все вкурсе...
Ваське числа десятого мая писал об этом. Потестить просил
Если картинка не найдена возвращает таблицу вместо nill.
Т. е.
aa = findimage(10, 20, 1020, 810, {"C:\\tmp\\image.bmp"}, 2)
if aa then
move(aa[1][1], aa[1][2]) -- ошибка, если картинка не найдется
end
Это работает для совместимости. Если параметры переданы строкой, то передаются старому парсеру, который также работает в пилотовском скрипте.
можно ли мечатать не безрезультатно о хотфиксе nil?
arr = dir("d:\\!lua", "*.exe", "norecursion")
работает корректно, раньше без пробела " norecursion" не работало - слепляло маску и флаг рекурсии.
НО с пробелом
arr = dir("d:\\!lua", "*.exe", " norecursion")
тоже работает. Т.е. либо любимый костыль с приведением к старой доброй строке (нет в ней ничего доброго ) либо ошибочно проставлена функция и сравнение не строгое, а используется поиск внутри строки.
findimage не допилен (вероятно и колор). Точнее массивы вроде доделали, основательно перелопатил свой скрипт по распознаванию приводя его в соответствии с реалиями и неожиданно встретил конвертацию возвращаемого имиджем результата из стрингов в числа. Убрал конвертацию - не завелось. Вся таблица состоит из стрингов:
a[1][1]=25 type: string
a[1][2]=5 type: string
a[1][3]=34 type: string
a[1][4]=16 type: string
a[1][5]=91 type: string
Прошу пофиксить пока у меня весь скрипт разобранный, чтобы потом к этому не возвращаться.
Про этот момент как-то даже мысли не возникало.
Финдимидж и финдколор проверь в нестабильной ночнушке.
Упс, оказалось две похожих функции.
Финдимидж подправил.
Спасибо. Отшуршало нормально. Я надеюсь там не tonumber?)) Хотя как оказалось данное преобразование настолько шустрое, что за одну секунду делает около десяти миллиардов о.О
А можно как-то улучшить редактор? От отсутствия подсветки синтаксиса колбасит. И ещё, научить UOPilot игнорировать по умолчанию своё окно, если оно перекрывает нужное.
Убрать в ночной версии сообщение в лог что луа загружен, при первом запуске скрипта.
build 14
Исправил функцию 'random()' в Lua, теперь возвращает число.
Если картинка или цвет не найдены, то 'findimage' и 'findcolor' в Lua возвращают nil вместо пустой таблицы.
Убрал сообщение 'Операция успешно завершена' выводившееся при остановке Lua скрипта.
Массивы, возвращаемые функциями 'findimage' и 'findcolor' в Lua, теперь числовые.
Исправил 'findwindow' при использовании из скрипта Lua. Если ничего не найдено, то возвращает "nil", а не пустую таблицу. При вызове без параметров, возвращает данные активного окна.
Хендл, возвращаемый функцией 'findwindow' в Lua, теперь число.
Размер сообщения, выводимого в лог, сейчас увеличен до 1к.
Приятный сюрприз
Не стабильная:
Команда 'get clipboard' очищает принимающий массив.
Убрал преобразование переменных в получаемом буфере обмена при использовании команды 'get clipboard %array'.
Починил 'clipboard' в Lua.
'clipboard(text)' - один параметр, установка;
'string = clipboard()' - без параметров, получение одной строкой;
'array = clipboard(0,"string","word")' - больше одного параметра, разбивка в массив по словам, или по строкам, или по словам и по строкам.
Оно костыль, ему пофиг кем, главное быть
Так тоже можно 'array = clipboard("string","word")'
build 15
Команда 'get clipboard' очищает принимающий массив.
Убрал преобразование переменных в получаемом буфере обмена при использовании команды 'get clipboard %array'.
Починил 'clipboard' в Lua.
'clipboard(text)' - один параметр, установка;
'string = clipboard()' - без параметров, получение одной строкой;
'array = clipboard(0,"string","word")' - больше одного параметра, разбивка в массив по словам, или по строкам, или по словам и по строкам.
Подправил передачу больших целых чисел из Lua. Больше не должны выводится в экспоненциальной форме.
Исправил ошибку в командах 'set hotkeystart' и 'set hotkeypause'.
Добавил в функцию 'findcolor' поиск цвета в загруженной области.
Добавил проверку захвата изображения по хендлу, при нажатии Ctrl+A для привязки скрипта к рабочему окну. Включается галочкой "Check image capture by handle", находящейся рядом с кнопкой "F" на форме скрипта. Если изображение не может быть получено, или возвращен черный квадрат, то берется родительский хендл и снова проверяется пока не будет получено изображение. В результате проверки в лог выводится цепочка проверенных хендлов и заголовок окна, необходимого для правильного определения цвета, либо сообщение об ошибке.
Добавил команду проверки захвата изображения по хендлу. Возвращает смещение по координатам и правильный хендл, либо 0.
'set #newhandle checkgetcolor (#x #y #handle)' // UoPilot, в переменные #x #y возвращает смещение.
'handle, offset_x, offset_y = checkgetcolor (handle)' -- lua
Исправил вывод в лог длинных сообщений.
Вынес.
Нестабильная ночнушка.
set #a findmemory (-1 value type %result 100 workwindow)
возвращает количество найденных либо код ошибки.
-1 - зарезервировано, обязательно
value - искомое значение. если строка не сплошная, то в кавычках.
type - тип предыдущего аргумента, также как в командах чтения\записи в память
%result - принимающий массив
100 - зарезервировано, обязательно
workwindow - хендл рабочего окна
Пока так.
В 64х битных процессах сканирует только первые 32 бита. Пока не нашел как вторые 32 бита перечислить.
findcolor некорректно работает с изображением в памяти. Левый верхний угол изображения обрабатывает правильно, а вот правый нижний глючит конкретно. Задаю диапазон поиска по ординате 439..444. Файнд типа нашёл требуемый пиксель, а параметр %arr[1 2] возвращает НУЛЬ. Кстати и в нулевой ординате такого пикселя нет.
И если не составит труда, просветите меня пожалуйста (хотя бы в общих чертах), в чём преимущества LUA? Насколько я понимаю сейчас именно в этом направлении развивается Пилот.
--lua
local t, z = os.clock(), 0
for i=1, 100000000 do
z = z + 1
end
log ("Затрачено времени: " .. string.format("%.3f", os.clock()-t) .. " мсек" .. " , z = " .. z)
set #t timer
set #z 0
for #i 1 100000
set #z #z + 1
end_for
set #t timer - #t
log Затрачено времени #t мсек, z = #z
end_script
Спасибо, а где бы поучиться этому?
WKnight, findwindow возвращает хендл стрингом.
Да-да-да... Без пол-литра не получится. Собственно мне и нужны примочки Пилота, финды .. винды, а про это там ни слова. Вот язык Пилота понятен даже с церковно-приходским образованием. Грубо говоря нужны примеры, а кто мне их на халяву даст? А за деньги ... я уже слишком стар, на пенсию учиться не получится. Всё равно спасибо Дарк,для меня ты Лайт.
Без конкретных примеров я не осилю. Метод тыка тут не сработает.
Если Кнайт доведёт до ума Файнды, больше ничего и не надо. А если всё-таки сделает поиск цветовой разницы с параметром типа (R-G(20), R-B(30)), то вообще не будет проблем. На этом принципе я сделал распознаватель текста, анализ 8-ми реперных точек, лично у меня даёт 100% результат, на любом фоне, при приличном рендеринге и работает достаточно быстро.
Нашёл примеры. Будем пробовать.
Столкнулся со странной проблемой. Финдимидж в lua синтаксисе возвращает два числа 4 и -5 и не возвращает при этом массив. В окне скрина _белый_ малевич. Это что?
Привязываемся к хрому.
set $var getwindowtext (workwindow)
log $var
set %arr findwindow($var)
log find: %arr[1 1] %arr[1 2]
вывод в лог:
2:13:10 4 (autosaved_4.txt, 16): Chrome Legacy Window
2:13:10 4 (autosaved_4.txt, 18): find:
Т.е. имя текущего рабочего окна успешно дергается, а вот найти финдом не может его.
getwindow - возвращает стринг
После сохранения по-прежнему съезжают относительные адреса. В случае с lua каждое сохранение = перезапуск пилота ибо все едет.
Uopilot не взаимодействует с орионом, можно как то починить? Не работает автомув, статы и прочее тоже не показывает.
Изображения могли быть полностью одноцветными, что должно было привести к тому, что все изображение становится игнорируемым фоном. Возможно где-то там проблема.
getimage() под луа работает,что возвращает и как вызывать ?
Работает, вызывать точно так же, возрващает массив.
local loaded_image = getimage(param1, param2, ....)
Второй вопрос :
подозреваю, что все или почти все. Записывается только чуть иначе - скобки другие.
{param, param, param, ...}
param - стрингом.
Т.е. прям так 'R(11)+G(73-80)+B(1)' ?
Думаю да. Сам не помню, с пол года назад обсуждали, допиливали.
Вообще там все относительно нативно совместимо везде. Разница только в паре операторов, где возвращается несколько значений (например в финдах код ошибки и таблица) и в скобках, если они вложенные.
Общее правило:
Если возвращается несколько значений, то они задаются:
var1, var2 = function()
Если скобки вложенные, то они превщаюатся из круглых в фигурные:
(param, (param), param)
(param, {param}, param)
Не стабильная ночнушка
Исправил возврат таблицы значений в команде 'findimage' в Lua, при отсутствии результата или ошибке поиска.
В команду 'findimage' добавил код ошибки '-7' - нечего искать, искомая картинка пустая.
Обнаружил случайно такую вещь, ошибкой не назовёшь, но не зная (как я до сегодня) её могут возникнуть логические ошибки, которые сразу бывает не так просто найти.
case: set #error 1 // такой оператор в конце switch не работает
case : set #error 1 // а вот так всё нормально
Исправил 'case:'.
Сделал восстановление "текущего каталога" при сохраненях\загрузках.
Исправил в функции 'findcolor' поиск цвета в загруженной области.
Поменял емайл.
--lua
clipboard ("раз два три") -- 3 слова
wait (300)
local arr = {}
arr = clipboard (0, "word") -- разбить по словам
log (#arr[1]) -- размер 4
ПОЧИНИЛ
--lua
log(type(windowfromcursor())) -- возвращает стринг
Ультимы нет, тестить не на чем. Там не стринги возвращает?
Починил 'set windowpos' в Lua. Теперь работает как функция 'windowpos (x, y, width, height [, handle])'. Не возвращает ничего.
Ток новую версию скачай.
if параметр зн.оп. значение then
while параметр зн.оп. значение do
for имя=начало, конец do
Убрал двойные скобки при вставке команд из меню по ПКМ в Lua, курсор устанавливается за скобками.
Расставил запятые в скобках, при вcтавке команд из меню по ПКМ в Lua.
При вcтавке команд из меню по ПКМ в Lua убираем признаки переменных.
Слегка изменил алгоритм вставки команд в скрипт из контекстном меню. Обязательные параметры не убираем.
Переделал подсветку синтаксиса в редакторе. Добавил возможность изменять категорию существующих ключевых слов и добавлять новые. Список слов указывается в секции "[Highlighter]" в конфигурационном файле пилота в параметрах оканчивающихся на " List" (появятся при сохранении настроек). Пример: "RW EndScript List=end_script,konec_skripta".
Вообще было бы круто по пкм вот этот списочек вставить, как операторов луа
https://www.lua.org/manual/5.1/index.html#index
Функции, а не C API и auxiliary library естественно.
В меню по ПКМ добавил раздел "Lua".
Добавил возможность комбинировать скрипт пилота с Lua. '--lua' обозначает начало Lua скрипта, '--endlua' соответственно конец.
log start
--lua
log ("lua")
--endlua
log finish
end_script
Переделал алгоритм комментирования строк, в связи с предыдущим пунктом. Теоретически должно работать.
Насколько я понял, просто последовательно выполняется скрипт на разных языках. Например, сначала кусок Пилотовский, потом на ЛУА, потом опять Пилотовский. Но у меня все переменные из первого куска уже недоступны. Если так и должно быть, тогда вопрос, а не проще запускать параллельный скрипт на lua ? Такой вариант ничего не теряет. Всё равно из lua кода ничего вернуть в Пилотовский код нельзя.
Да Кнайт, что ещё хотел спросить. Мой пример по некорректной работе findimage, который я выкладывал в "пожеланиях", какие-то соображения есть на эту тему? В lua пока ещё этот пример не тестировал.
.
При наличии функций в куске Луа goto не работает. Именно такая ситуация у меня и была. Где они должны располагаться? Первыми, в самом начале?
Ну вроде уж подробней не бывает.
Прикрепленные файлы
ErrorFindImage.7z ( 6,88 килобайт )
Кол-во скачиваний: 68
Это вариант при 100% совпадении и без deviation. То есть совпадение картинок 100%. Может это поможет пролить свет на проблему.
И в версии 2.39 всё работает как часы, все три варианта находит со 100% результатом.
Ну и собственно я то эту проблему методом тыка обрулил. Я же не для себя преференции выбиваю. Просто если выплыло у меня, обязательно выплывет где-нибудь и у других.
Прикрепленные файлы
ErrorFindImage2.7z ( 1004 байт )
Кол-во скачиваний: 56
--lua
local arr, count = findimage(0, 0, 1920, 1080, "C:\\tre.bmp")
hint (a, c)
там и 4 или -5? падало в arr. Подозреваю где-то не в ту переменную пишет ошибки.
Пришлось сделать некоторое допущение, и можно сказать, что
Подправил возврат кода ошибки функциями 'findimage' и 'findcolor' в Lua, при неправильном указании параметров.
Возможно это: https://forum.uokit.com/index.php?s=&showtopic=67903&view=findpost&p=420953
Точно, спасибо.
findcolor в памяти не работает.
1) вариант когда работает (хотя тоже не на всём скрине)
set %pic GetImage (508 243 970 777)
set #sp findcolor (0 0 20 0 ...
2) вариант когда НЕ работает
set %pic GetImage (0 0 970 777)
set #sp findcolor (508 243 528 243 ...
И вот ещё какая штука
GetImage (0 0 1919 1079)
Если потом сохранить в файл, то сохранит именно эту область 1920х1080 с остатками рабочего стола и чернотой, где рабочий стол закончился. В принципе ничего такого, просто для информации.
Да, вот ещё, для информации. Рабочее окно располагалось на 2-ом мониторе.
Примерно выяснил где глюк колора.
set %pic GetImage (0 0 970 777)
set #type %pic[1 1]
set #sp findcolor (508 243 528 243 1 1 (R(0-255)) %sp %pic[1 1])
save_array %sp "C:\TMP\_memory.txt"
Первый столбец всё как надо, а вот второй столбец все нули, грубо говоря путает ординату поиска.
Похоже я один только и пользуюсь (пытаюсь) поиском в памяти.
set %get [1] LoadImage (скрин_окна.bmp)
set %image [1] LoadImage (Original.bmp)
log clear
log mode compact
set #a Findimage(0 0 1032 956 (%image [1 1]) %arr %get [1 1] 100)
if #a > 0
log #a %arr [1 1] %arr [1 2] %arr [1 3] %arr [1 4] // координаты искомой картинки
end_if
set #a Findimage(300 0 700 956 (%image [1 1]) %arr %get [1 1] 100)
log #a // не найдено
set #a Findimage(0 100 1032 956 (%image [1 1]) %arr %get [1 1] 100)
log #a // не найдено
end_script
Пилот поверх всех окон, файл/открыть скрипт - форма за окном пилота и не видна.
--lua
arr, err = findcolor(0, 0, 100, 100, 1, 1, {"r(0-255)"})
log(arr,err) -- получаю nil 0
Что я делаю не так?
local a = findcolor("0, 0, 10, 0, 1, 1, 0, %arr, 2")
log (#arr) -- а вот так ищет
Получается новый вариант синтаксиса не работает.
попробуйте явно указать метод:
arr, err = findcolor(0, 0, 100, 100, 1, 1, {"r(0-255)"},2)
r(0-255) диапазон так и не понял как искать ни в старом, ни в новом варианте.
Ещё давно возник у меня такой вопрос, конечно я обхожу эти "рифы", но решился всё-таки озвучить. Почему, например, такая конструкция у меня выполняется более 4 секунд?
set #tmp findcolor (244 639 825 922 1 1 (R(0-255)) %tmp)
Подозреваю, что что-то не так с массивом. Конечно корифеи скажут, а зачем такое вообще надо. Но мне часто требуется не просто искать конкретный цвет, а именно получить цвета всех пикселей конкретной зоны экрана (зачастую немаленькой, ввиду разброса объектов), желательно минимальным количеством вызова файнда, для детального анализа. Получать из памяти такой массив я пока не пробовал (жду доводки файнда). Но 4 секунды, на мой взгляд, как-то не вяжутся с логикой процесса.
Обработка в lua любого массива данных занимает доли секунды, вопрос как получить эти данные с минимальными затратами времени.
И всё-таки ещё раз "о главном". Конечно запрограммировать можно и "свалку" данных. Но не все будут этим заниматься, а на мой взгляд, нужна реализация поиска findcolor-ом цветовой разницы между RGB каналами. У меня без этого никак невозможно правильно запрограммировать поиск объектов при смене времени суток в игре.
Да и не только при смене времени суток, часто встречаются "переливающиеся" объекты, их тоже можно "вычислить" только анализом RGB.
И опять же. С помощью таких конструкций, скрипт собирал статистику и то, что на первый взгляд казалось в принципе невозможным запрограммировать, на поверку оказалось возможным, иногда "на грани фола", но возможным.
Я тестировал все функции связанные с обработкой изображений, от printscreen до getimage. И все они выполняются примерно 3 сотых секунды, хоть в Пилоте, хоть в lua. Собственно поэтому я и пытаюсь вызывать эти функции ОДИН раз, потому что весь остальной скрипт на lua (далеко не маленький) выполняется 13-18 ТЫСЯЧНЫХ секунды.
С загрузкой из файла массива, потом сохранением в файл (правда всё на RAM) и всего 18 тысячных.
readmem не совсем понимаю как пристроить под это дело. В lua я мало что знаю, раньше я просто использовал move в указатель, выделив соответствующую память.
Нужно Кнайту просто сделать этот самый move.
Насколько я понял getimage возвращает параметр длины 3 байта * кол-во пикселей + 2 байта.
Хотя наверное move не прокатит. 3 байта - это формат файла, их не пристроишь никак под переменные.
Проще наверное посмотреть, почему файнд так начинает тормозить.
Вот если бы readmem мог считывать в побайтовый массив, типа как в строку, только без ограничения по длине. Тогда можно было бы сделать быстрый обработчик.
--lua
fileBinary = require"luaPlugins\\FileBinary"
do
local tab = ""
local deep = 0
function table.show(t, comment)
-- Пишем в лог комментарий.
deep = deep + 1 -- Уровень вложенности вызовов функции.
--log(comment .. commentSended .. deep)
if comment ~= nil and deep == 1 then
log(comment)
end
if type(t) == "nil" then log("table is nil")
elseif type(t) == "string" then log('table is string: "'..t..'"')
elseif type(t) == "number" then log('table is number: '..t)
elseif type(t) == "table" then
local elementsInTable = 0
for k,v in pairs(t) do
if type (v) == "table" then
if type(k) == "string" then
log(tab..'table: "'..k..'"')
else
log(tab..'table: '..k)
end
tab = tab .. " "
table.show(v)
tab = string.sub(tab, 1, -5)
elementsInTable = elementsInTable + 1
else
elementsInTable = elementsInTable + 1
if type(v) == "string" then v = '"'..v..'"' end
if type(k) == "string" then k = '"'..k..'"' end
log(tab..""..k.." = "..v)
end
end
if elementsInTable == 0 then log("table is empty") end
else
log('table is unknow data type')
end
-- Пишем в лог комментарий.
deep = deep - 1 -- Уровень вложенности вызовов функции.
end
end
log("clear")
-- Получаем изображение в массив.
function imageToArray (startX, startY, endX, endY, appWindow)
local bitmap = {}
local address, w, h, l = getimage(startX, startY, endX, endY, appWindow)
log (address, w, h, l, "n56")
local pos = 1
for i=address, address + h*(l) - 1, l do
for j=i, i+w*3 - 1 do
bitmap[pos] = readmem(j .. " b")
pos = pos + 1
end
end
saveimage(address, "d:\\!lua\\!test.bmp")
deleteimage(address)
return bitmap
end
function binary(file, pos, val, i, j)
file:seek("set", pos)
if i == nil then i = 1 end
if j == nil then
j = #val - 1
else
j = i + j - 1
end
-- log(i, j)
for i=i, j do
file:write(string.char(val[i]))
end
end
-- file - хендл или имя файла
-- w - ширина изображения
-- h - высота изображения
function writeBmp (file, bitmap, w, h)
if type(file) == "string" then
file = io.open(file, "w+b")
end
file:seek("set", 0)
local l = math.ceil (w*3/4) * 4 -- Длина строки с выравниванием.
local alignment = l - w*3
local fileSize = l * h + 0x36
log(fileSize)
-- Заголовок
file:write(string.char(0x42))
file:write(string.char(0x4D))
file:write(string.char( -- Размер файла.
fileSize%256,
floor(fileSize/256),
floor(fileSize/65536),
floor(fileSize/16777216)))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0x36)) -- Оффсет на битовую маску.
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0x28))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(floor(w%256))) -- Ширина
file:write(string.char(floor(w/256)))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(floor(h%256))) -- Высота
file:write(string.char(floor(h/256)))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0x01))
file:write(string.char(0))
file:write(string.char(0x18))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0x74))
file:write(string.char(0x12))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0x74))
file:write(string.char(0x12))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
file:write(string.char(0))
local i = #bitmap - w*3 + 1
for i = w*3*(h-1)+1, 1, -w*3 do
-- log("!!!", #bitmap, file:seek() ,i, h, w, w*3, l)
binary(file, file:seek(), bitmap, i, w*3)
for j = 1, alignment do
file:write(string.char(0))
end
end
-- for pos=0x36, 0x36 + #bitmap - 1, l do
-- log("!!!", #bitmap, pos ,i, h, w, w*3, l)
-- binary(file, pos, bitmap, i, w*3)
-- i = i - w*3
-- end
end
function getAvg(path, appWindow, timeout, startX, startY, endX, endY)
local countImages = 0
local w = endX - startX + 1
local h = endY - startY + 1
local s = w * h * 3 -- количество полезных пикселей (без выравнивания)
local sum = {} -- сумма значений каждого канала всех изображений.
for i = 1, s do
sum[i] = 0
end
-- Собираем изображения в течении заданного времени.
local myTimer = os.clock() + timeout
while myTimer > os.clock() do
-- Массив со значениями каналов.
local bitmap = imageToArray (startX, startY, endX, endY, appWindow)
--table.show(bitmap)
-- Суммируем изображения
for i = 1, s do
sum[i] = sum[i] + bitmap[i]
end
countImages = countImages + 1
end
-- Находим среднее значение
local avg = {}
for i = 1, s do
avg[i] = sum[i] / countImages
end
--table.show(avg, "avg")
writeBmp (path, avg, w, h)
end
function getStatic (path, appWindow, timeout, startX, startY, endX, endY)
local bitmap = imageToArray (startX, startY, endX, endY, appWindow)
local w = endX - startX + 1
local h = endY - startY + 1
local countImages = 0
-- Собираем изображения в течении заданного времени.
local myTimer = os.clock() + timeout
local bench = os.clock()
while myTimer > os.clock() do
-- Массив со значениями каналов.
local scr = imageToArray (startX, startY, endX, endY, appWindow)
log("Битмап в массив за:" .. os.clock() - bench .. " сек.")
bench = os.clock()
-- Закрашиваем нестатичные пиксели.
for i = 1, #bitmap, 3 do
if bitmap[i ] ~= scr[i ] or
bitmap[i+1] ~= scr[i+1] or
bitmap[i+2] ~= scr[i+2] then
bitmap[i ] = 0
bitmap[i+1] = 255
bitmap[i+2] = 0
end
end
log("Поиск статики за:" .. os.clock() - bench .. " сек.")
countImages = countImages + 1
end
writeBmp(path, bitmap, w, h)
end
if workwindow ~= tonumber(windowhandle()) then
log("Привязка должна быть к пилоту.")
workwindow = tonumber(windowhandle())
alarm("online")
return
end
startX, startY, endX, endY = 194, 286, 277, 434
appWindow = findwindow("Crossout 0.")[1][1]
log(appWindow)
--if 1 then return end
local cpuTime = os.clock()
-- getAvg("d:\\!lua\\test" .. os.time().. ".bmp", appWindow, 5, startX, startY, endX, endY)
getStatic("d:\\!lua\\test" .. os.time() ..".bmp", appWindow, 60,
193, 286
,
208, 432
)
getStatic("d:\\!lua\\test" .. os.time() ..".bmp", appWindow, 60,
193, 615
,
210, 762
)
log(os.clock() - cpuTime)
alarm("online")
--lua
local binary = {}
function binary.getBitmapOffset(file)
return binary.readInt(file, 0x0A)
end
function binary.readInt(file, pos)
file:seek("set", pos)
local a = string.byte(file:read(1))
file:seek("set", pos + 1)
local b = string.byte(file:read(1))
file:seek("set", pos + 2)
local c = string.byte(file:read(1))
file:seek("set", pos + 3)
local d = string.byte(file:read(1))
file:seek("set", pos + 4)
return a + b * 256 + c * 65536 + d * 16777216
end
function binary.writeInt(file, pos, val)
file:seek("set", pos)
return file:write(
string.char(math.fmod(val, 256),
math.fmod(val, 65536)/256,
math.fmod(val, 16777216)/65536,
val/16777216)
)
end
function binary.readByte(file, pos)
file:seek("set", pos)
return string.byte(file:read(1))
end
function binary.writeByte(file, pos, val)
file:seek("set", pos)
return file:write(string.char(val))
end
function binary.readArray(file, pos, sz)
local result = {}
file:seek("set", pos)
local s = file:read(sz)
for i=1, #s do
table.insert(result,string.byte(string.sub(s, i, i)))
end
return result
end
-- Пишет в бинарном виде данные в файл file
-- начиная с позиции pos
-- из таблицы или строки val
-- начиная с позиции i внутри val
-- размером j внутри val
-- Запись полный тормоз.
-- Массив 2.296 Мб/сек.
function binary.writeArray(file, pos, val, i, j)
file:seek("set", pos)
if i == nil then i = 1 end
if j == nil then
j = #val - 1
else
j = i + j - 1
end
log(i, j)
for i=i, j do
file:write(string.char(val[i]))
end
end
return binary
--f = io.open("d:\\test.bmp", "r+b")
--log(f)
--log(binary.readInt(f, 0))
--log(binary.writeInt(f, 0, 0x123456ab))
--log(dec2hex(v))
--v="1234567890"
--log(string.byte(v, 1, 10))
--t = binary.readArray(f, 0, 4096)
--local j = 0
--local t = {}
--for i = 1, 40100 do
-- if j < 255 then
-- j = j + 1
-- else
-- j = 1
-- end
-- t[i] = j
--end
--binary.writeArray(f, 0x36, t, 1, 40100)
--local j = 0
--local t=""
--for i = 1, 40100 do
-- if j < 255 then
-- j = j + 1
-- else
-- j = 1
-- end
-- t = t .. string.char(j)
--end
--
--f:seek("set", 0x36)
--myTimer = os.clock()
--for i=1, 1000 do
-- f:write(t)
--end
--log(os.clock() - myTimer)
Вообще самым быстрым вариантом будет работа с указателями и прямое чтение памяти. Но в lua этого нет. Более того в луа нет таких типов данных, как byte и int. Тут все на double. Это однозначно приведет к проблеме скорости, т.к. все byte должны будут приведены к типу double. Объем изображения приличный и эти преобразования уже начинают давать свои проблемы. Вообще для подобного анализа луа не лучший вариант, хотя однозначно можно. Если это именно в плане подготовки изображений, т.е. какой-то предварительный анализ для последующего использования статистики, кусков изображений и т.д., то этой скорости будет достаточно, если речь идет о реал тайм обработке, то могут возникнуть вопросы (очень сильно зависит от размера изображения).
Отдельная просьба к кнайту, т.к. это минимум второй человек, который озадачился данным аспектом - сделать пуш битовой маски в массив луа. Что-то вроде:
local arr = BitmaskToArray(pointer)
ArrayToBitmask(arr, pointer)
Всяко лучше, чем имиджи насиловать, трудозатраты, по идее там сиволические на это дело.
Вопрос, самый простой способ получить доступ к конкретному символу строки в lua. Случайно обнаружил, что работают и chr и ord. Оператор ord(str) возвращает значение первого символа строки.
local ch = string.sub (str, pos, 1)
Дарк, я так и не понял в каком формате хранятся данные, которые даёт getimage. Читаю readmem по байтам и что-то не понимаю логики. Тех байтов, которые потом кладутся в bmp картинку я не нахожу.
В bmp кладутся чистые байты без минусов, для каждого канала 0-255. Может я читаю в другом формате? Типа word с минусами?
--lua
log "clear" log "mode compact"
local address, w, h, len=getimage(0, 0, 5, 5)
local arr, k = {}, 1
for i=0, h-1 do
arr[k]={}
for j=0, len - (len - w * 3 + 1), 3 do
local b=readmem(address + len * i + j, "b", windowhandle())
local g=readmem(address + len * i + j + 1, "b", windowhandle())
local r=readmem(address + len * i + j + 2, "b", windowhandle())
-- log (r, g, b)
table.insert(arr[k], r + g * 256 + b * 65536)
end
k=k+1
end
for i=1, #arr do
log(table.concat(arr[i], " ")) -- вывод массива в лог
end
Cirus, спасибо огромное, всё работает как часы, получился быстрый полноценный файнд, ищет только те пиксели, которые нужны.
Дарк, ты абсолютно прав, действительно скорость вызова внешних функций намного хуже всех остальных вычислений в lua.
Я пока вот так проэксперементировал и скорость выросла ровно в 2 раза. Мне обычно нужен анализ всего 2-х цветов и я стал читать сразу 2 байта вместо одного.
tmp=readmem(index+1,"w",windowhandle())
red=math.modf(tmp/256)
green=math.fmod(tmp, 256)
Поэтому по уму надо или плагин писать или может Кнайт что-то придумает.
Можно ещё в строку читать кусками до 255 байт, пока это лучший вариант.
str="0"..chr(0).."1".. chr(1).."2"
log(string.byte(str,4))
Всё анализируется без проблем.
Обработка строками (пока правда мало вариантов тестировал) дала отличный результат. Побайтово я получал массив для 6 (2 строки по вертикали) пикселей 5 тысячных секунды, построково в 10 раз быстрее.
--lua
resultarray, count = dir ([[C:\Windows]], "*.bmp", "norecursion")
log (resultarray, count)
Файлы *.lua не оторбажаются по умолчанию при открытии скриптов. Приходится выставлять маску *.*.
при выключении галки "добавлять пробелы", они все равно продолжают добавляться. Для луа не удобно.
В последней ночнушке стали вылетать access violation. Вылетает при старте скрипта. Стабильного воспроизведнеия добиться не удалось. Тем не менее подозреваю, что это как-то связано с остановкой скрипта, т.к. эта проблема возникала только после ручной остановки скрипта.
А скрипт то в каком формате?
lua
Хотя - логика - это сильно сказано, под логикой я подразумеваю, что раньше запоминал какие клавиши жал, куда мышкой кликал, теперь всё это кануло в лету. Наплевать куда кликал, всё сразу анализируется.
В этом и суть. Пилот - это кладезь недокументированных возможностей и невылизанных моментов, lua же вылизан и четко описан. Вылизывание занимает очень много времени. Реалии таковы, что вылизывать код будешь разве, что для себя - люди не готовы тратить на это время. Для себя вылизывать зачастую смысла не так много, т.к. человек с мозгами едва ли будет вводить что попало, разве, что тестер. Ирония в том, что эти "невылизанные" моменты в итоге приводят к падению серверов, когда человек использует вполне легальное и описанное API макросов. Вот и получается, что вылизывание сейчас - это для себя получая удовольствие от качественного конечного продукта.
Стремительный бег времени, мы несёмся к новым знаниям, не успевая закрепить старые. Когда-то я считался неплохим специалистом, многие мои друзья уехали в Америку. Но я русский, здесь родился, здесь и помру. И за 30 лет я из спеца превратился в отстой. Хотя мне уже на покой пора, так что я не переживаю.
Страшно вспомнить, была такая машинка в СССР "Наири" в машинном зале. С перфокарт я начинал. На Искре 1030 закончил.
Ну время хоть и идет, но с вами хотя бы приятно разбирать какие-то моменты - понимаешь, что у человека есть голова на плечах.
Спасибо Дарк на добром слове. Буду принимать участие в доводке Пилота, пока есть силы и интерес, найду ошибки - сообщу. Будут пожелания - выскажу. Собственно мне и игра не интересна, интересно когда она играет за меня. Интересен процесс. Кнайту - терпения и удачи.
Вынужден свернуть все работы по переходу на lua. Обработка изображений в памяти невозможна. Читать байтами слишком медленно, а строками невозможно.
Сия конструкция не работает ss=readmem(ind,"s",numbyte,h)
Точнее работает пока не наткнётся на нуль или 255 байт. И то и другое считает концом строки и не читает ВСЕ положенные numbyte.
А вообще и строками читать тоже не самый лучший вариант, вот если бы сразу весь массив получить, тогда бы я и блоху, скачущую по экрану 100 пиксельными прыжками отловил.
Не совсем я понял эти строки, с одной стороны, как в старом паскале мерилом строки является нулевой байт, а с другой совершенно иная интерпретация конца строки, так возникает вопрос, а почему тогда ограничение в 255 байт?
Конечно можно извратиться и читать непрочитанное байтами, но как-то не эстетично будет, да и опять же лишние тормоза.
Кнайт, сделай пожалуйста мувик (move) без анализа содержимого.
Не совсем корректно написал, первый байт со значением 255 читает.
local rmem = require "ffi".cast
print = log
print "clear"
print "mode compact"
local a = getimage(694, 146, 708, 155)
log (a)
log (readmem(a, "b"))
log (rmem("char*", a)[0])
local t = os.clock()
for i = 1, 1000 do
local tmp = readmem(a, "b")
end
log (os.clock()-t)
local t = os.clock()
for i = 1, 400000000 do
local tmp = rmem("char*", a)[0]
end
log (os.clock()-t)
https://luajit.org/ext_ffi.html
тут как раз пример по изображениям. Там еще и по математике очень сильно выиграть можно.
Я тебе выше дал аналог реадмема, который напрямую без пилотовских функций получает доступ к памяти.
1000 итераций пилота
420 000 000 итераций прямого чтения
занимают примерно то же самое время.
Больше не нужно читать строками - читай просто память побайтовов напрямую.
local rmem = require "ffi".cast -- в шапку.
local val = rmem("char*", ADDRESS)[0] -- читаем 1 байт.
local rmem = require "ffi".cast -- в шапку.
local address, width, height, length = getimage ( 148, 253 , 228, 279 )
for h = 0, height - 1 do
address = address + length * h
for w = 0, width do
address = address + 1
log (rmem("unsigned char*", address)[0])
end
end
--lua
-- сделать привязку к нужному окну
local rmem = require "ffi".cast
local address, width, height, length = getimage (0, 0, 10, 10)
log "clear" log "mode compact"
local addr = address
local arr, k = {}, 1
for w = 0, height - 1 do
address = addr + length * w
arr[k]={}
for i=address, address + length - (length - width * 3 + 1), 3 do
local b=rmem("unsigned char*", i)[0]
local g=rmem("unsigned char*", i+1)[0]
local r=rmem("unsigned char*", i+2)[0]
--log (r, g, b)
table.insert(arr[k], r + g * 256 + b * 65536)
end
k=k+1
end
for i=1, #arr do
log(table.concat(arr[i], " ")) -- вывод массива в лог
end
ОК. Спасибо cirus, но всё равно завтра, сегодня я уже устал.
Send217/send (say не тестил) в lua делает обрезание пробелов. Попытка отправки send(" ") приводит к остановке скрипта (видимо крашит скрыто). В последней нестабильной бете при этом еще и перезапускает скрипт о.О.
Починим. Только я финды разобрал, а собрать вдохновения нет, та еще и приболел малость.
Там вроде с точками или знаками препинания в целом какие-то проблемы еще (по слухам). А в нестабильной сдвигает каретку влево не то при перезапуске автоматическом не то при попытке пробел напечатать (сам видел).
log(mouseclickdelay (20))
вернет старый delay, но установит корректно. Последующий вызов
log(mouseclickdelay ())
уже вернет 20.
Т.е. логично было бы, чтобы возвращало установленное значение, а не старое при вызове с параметром.
--lua
arr, err = findcolor(0, 0, 1920, 1080, {5318912}, 2)
hint(err)
(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(144)main->"[C]"->(-2)send217->"[string "--lua..."]"->(140)main-> end
При send217(some_func_return_none()) набирается дикий стек.
Причем этот дикий стек идет даже перед объявлением пременных в шапке скрипта.
Скинь че-нить, чтоб я в дебаге мог походить. Мож с моей стороны что-то интересное видно будет.
--lua
send217()
end_script ()
--lua
--log = print
do
local tab = ""
local deep = 0
function table.show(t, comment)
-- Пишем в лог комментарий.
deep = deep + 1 -- Уровень вложенности вызовов функции.
--log(comment .. commentSended .. deep)
if comment ~= nil and deep == 1 then
log(comment)
end
if type(t) == "nil" then log("table is nil")
elseif type(t) == "string" then log('table is string: "'..t..'"')
elseif type(t) == "number" then log('table is number: '..t)
elseif type(t) == "table" then
local elementsInTable = 0
for k,v in pairs(t) do
if type (v) == "table" then
if type(k) == "string" then
log(tab..'table: "'..k..'"')
else
log(tab..'table: '..k)
end
tab = tab .. " "
table.show(v)
tab = string.sub(tab, 1, -5)
elementsInTable = elementsInTable + 1
else
elementsInTable = elementsInTable + 1
if type(v) == "string" then v = '"'..v..'"' end
if type(v) == "boolean" then v = '"'.. tostring(v)..'"' end
if type(v) == "function" then v = '"'.. tostring(v) ..'"' end
if type(k) == "string" then k = '"'..k..'"' end
log(tab..""..k)--.." = "..v)
end
end
if elementsInTable == 0 then log("table is empty") end
else
log('table is unknow data type')
end
-- Пишем в лог комментарий.
deep = deep - 1 -- Уровень вложенности вызовов функции.
end
end
local dbg = {}
dbg.trace = 1 -- Отображение стека
dbg.line = 1 -- Отображение номеров строк
dbg.code = 1 -- Отображение исходного кода
dbg.source = 1 -- Отображение источника кода(адрес файла, строка и т.д.)
dbg.source_abs = 0 -- Абсолютные адреса файлов.
dbg.tab = 75 -- Выравнивание исходного кода в символах.
-- стек выравнивание код
--(213)main-> mycall()
--(213)main->(209)mycall-> file_echo()
-- стек выравнивание код
dbg.file = {} -- Настройки файла лога
dbg.file.enable = 1 -- Включить логирование в файл
dbg.file.path = "lua_log.txt" -- Путь файла лога
dbg.file.append = 0 -- Дописывать лог (не удалять старый)
dbg.file.handle = nil -- Хендл файла
dbg.buffer = {} -- Буфер с файлами скриптов.
dbg.homepath = [[i:\!sandboxie\wxLua\drive\C\LuaJIT-2.0.5 x86 bin_2\]] -- Копируем адрес директории с пилотом для
-- преобразования абсолютного в относительный.
-- Очень сильно экономит такты.
if dbg.file.enable == 1 then
if dbg.file.append == 1 then
dbg.file.handle = io.open("lua_log.txt", "a+b")
else
dbg.file.handle = io.open("lua_log.txt", "wb") -- Стираем файл.
-- dbg.file.handle:close() -- Стираем файл.
-- dbg.file.handle = io.open("lua_log.txt", "a+b")
end
end
function dbg.func()
local result = ""
local short_src = ""
local source_line = ""
local source_is_file = nil
local info = debug.getinfo(2,'nSl')
-- table.show(info)
if info then
-- Включено логгирование строк исходника.
-- Только вычлнение строки,
-- конкатенция после получения стека.
if dbg.code == 1 then
local source_line_n = info.currentline
local line_pos = 0
-- Если источник кода внешний файл, то
-- подгружаем файл в источник вместо адреса файла.
if string.sub(info.source,1,1) == "@" then
source_is_file = true
local source_file = io.open(string.sub(info.source, 2), "r")
info.source = source_file:read("*a")
source_file:close()
end
-- Находим строку с кодом в исходнике.
for i=1, source_line_n - 1 do
--log("i: "..i.."source_line_n: "..source_line_n - 1)
line_pos = string.find(info.source, "\n", line_pos +1)
end
local line_end = string.find(info.source, "\n", line_pos +1)
source_line = string.sub(info.source, line_pos + 1, line_end - 1)
-- result = result.."\t"..source_line
end
-- Получаем стек, пути.
if dbg.trace == 1 then
for i=3, 100 do
if info then
if not info.name then info.name = info.what end
-- Добавление источника.
if dbg.source == 1 then
if short_src ~= info.short_src then
if i > 3 then
-- Преобразуем абсолютный путь в отностиельный.
if source_is_file and dbg.source_abs == 0 then
local prefix = string.sub(short_src, 1, #dbg.homepath)
if prefix == dbg.homepath then
j=i
short_src = string.sub(short_src, #dbg.homepath + 1)
end
end
result = '"'..short_src..'"->'..result
end
short_src = info.short_src
end
end
-- Добавление стека
result = "("..info.currentline -1 ..")"..info.name .. "->" .. result
else
break
end
info = debug.getinfo(i,'nSl')
end
end
else
return
end
-- Добавляем строку исходника.
if dbg.code == 1 and dbg.code == 1 then
if dbg.trace == 1 then
result = result..string.rep(" ", dbg.tab-#result)..source_line
else
result = tostring(info.currentline)
result = result..string.rep(" ", 5-#result).."-> "..source_line
end
end
log(result)
if string.sub(result, -1) == "\r" then
result = result .. "\n"
else
result = result .. "\r\n"
end
if dbg.file.enable == 1 then
dbg.file.handle:write(result)
dbg.file.handle:flush()
end
-- log(source_line)
end
function dbg.enable (state) -- Вкл|выкл лога. nil, false, 0 - выключают, любые другие значения включают.
if state and state ~= 0 then
if dbg.line == 1 or dbg.trace == 1 then
debug.sethook (dbg.func, "l")
end
else
log "disable debug"
debug.sethook ()
end
end
return dbg
Unstable
02.12.2018 Build 016.16
Исправил эксепшен, возникающий при перезапуске Lua скриптов.
Unstable
07.12.2018 Build 016.17
Добавил "*.lua" в маску по умолчанию, в диалоги открытия\сохранения скриптов.
Исправил галочку "Добавлять пробелы", слегка переделал алгоритм.
Исправил 'dir' в Lua. Если ничего не найдено, то возвращает "nil", а не пустую таблицу.
В хелп с Wiki, который вызывается по "F1" или по ПКМ на операторе в скрипте, добавил команды Lua. Какую справку показывать, Lua или обычную, определяется по предшествующему комментарию.
В "Перекачать всё с Wiki" добавил скачивание Lua вариантов команд.
Исправил эксепшен при использовании 'send' без параметров.
Убрал зацикливание одинокого скрипта Lua без признака конца скрипта "--endlua".
Добавил редактор "Подсветки синтаксиса" в меню "Настройки".
Исправил ошибку "EConvertError '^xx'", где "хх" номер скрипта, иногда возникающую при выполнении процедур.
Мне нужен пример, для воспроизведения ошибки.
call test
proc test
set #handleWin findWindow (Калькулятор)
set workwindow #handleWin
end_proc
end_script
local mic=findwindow("Микшер")
if mic==nil then -- Если окно Микшера громкости не найдено
...
В Вашем случае нужно смотреть, чтобы значение #handleWin , было более нуля.
Нет, тут вопросы к Кнайту, попробовал, без запущенного калькулятора вешает Пилот наглухо. Хотя я бы ни в жизнь не запустил такой ненужный, да ещё и глюкавый оператор как proc.
Обнаружил вот такую ошибочку.
local p,w,h,l=getimage(655,938,684,938,ww)
saveimage(p,[[image.bmp]]) -- размер картинки 30 х 88 вместо 30 х 1
deleteimage(p)
ctrl-Y отвалился. (Противоположность ctrl+z). Так же был странный глюк, когда ctrl+Y начинал стирать строки. Это было как-то связано с выделением строки.
По ходу дела минимальная зона захвата getimage - 2x2
Во во,я и говорю - Far
Пилот свернутый в трей исчезает из трея после перезапуска проводника. Потом его не достать - только перезапускать. Я уже кидал сколько-то лет назад почему так происходит и что нужно сделать чтобы пофиксить)
Я надеялся, что со временем оно потеряет актуальность
В последней нестабильной бете findimage встал колом. Начал разбираться - там по x не отсекает область должным образом - ищет значительно шире.
set windowpos в луа отсуствует. Есть только get.
После запуска/остановки lua скрипта позиция в редакторе улетает вначало. Запоминать бы. А то тестовых запусках прокручивать сотни строк глаз дергаться начнет)
mic=findwindow("Микшер") -- Поиск хендла окна Микшера громкости
windowpos(100,100,800,0,mic[1][1]) -- Растягивание окна Микшера громкости, для гарантии отображения всех устройств
Проверил, в новой версии тоже работает, во всяком случае с Микшером работает.
Странно. Раньше не работало точно, фикса не помню. Буквально на днях не мог сдвинуть окно. Подозреваю, что версия была старая либо хендл дочерний какой-то. Вобщем вопрос снят.
А что насчет доступа к переменным из параллельных скриптов луа? У нас сейчас одна машина или их пачка? Получится ли создать некоторый массив:
global = {} -- видимый из всех скриптов
Будет прилинкован некоторый массив локальный.
global[my_name] = my_array_or_table_or_what_i_want
Дабы не забивать скрипт upvalue (lua не очень это любит, тем более в корень), инициализировать его можно функцией. Т.е. выглядеть в коде должно примерно так:
local my_name_for_global = global_vars()
my_name_for_global[my_name_of_field] = my_data
От практики использования индексов вкладок в рамках lua предлагаю отказаться, т.к. это пораждает несколько проблем:
1) Скрипты путешествуют по вкладкам.
2) Зачастую это ухудшает читаемость, т.к. нужно помнить и сопоставлять индексы скриптам.
3) Использовать возврат индекса по имени скрипта тоже бывает затруднительно, т.к. скриптов может быть несколько с похожими именами, а при изменении скрипта, как правило, он сохраняется под новым именем.
1) в нестабильной бете куда-то делись сообщения об ошибках (последней)
2) В пилоте не могу выполнить следующий код:
package.path = [[.\luaPlugins\winapi\?.lua;]] .. package.path
--package.path = [[.\winapi\?.lua;]] .. package.path
--package.path = [[.\glue\?.lua;]] .. package.path
package.loaded.winapi = nil
package.loaded.windowclass = nil
winapi = require [[winapi]]
require'winapi.windowclass'
win = winapi.Window{
w = 500, --all these are "initial fields"
h = 300,
title = 'Lua rulez',
autoquit = true, --this is to quit app when the window is closed
visible = false, --this field is from BaseWindow
}
function win:on_close() --this is an event handler
print'Bye'
end
print(win.title) --this is how to read the value of a property
win.title = 'Lua rulez!' --this is how to set the value of a property
win:show() --this is a method call
os.exit(winapi.MessageLoop()) --start the message loop
2) Падает с эксепшеном "деление на ноль" на строке "winapi = require [[winapi]]"
Если чуть чуть поковыряться, то ему похоже не нравятся строки типа
local maxn = maxn or 1/0
если их убрать, то падает в другом месте, хотя они даже не вызываются.
у меня падает ссылаясь на loop загрузку либо повторную загрузку модуля о.О
1) какие именно, в луа там вроде ниче не ковырял.
2) че-то нет идей.
Unstable
15.12.2018 Build 016.18
Исправил присваивание 'workwindow' в процедурах. Присваивание срабатывало только на вызывающий скрипт.
Убрал кусочек отладочной информации забытый недавно в финдколоре.
В редакторе скриптов отключил горячую клавишу удаления текущей строки, и для функции Redo изменил на Ctrl+Y.
Исправил минимальные размеры захватываемой картинки в команде
'getimage' при работе по хэндлу.
Исправил исключение при работе по хэндлу в команде 'getimage', когда начальные координаты были больше конечных.
Убрал напоминание о том, что не указано рабочее окно, при старте скрипта по горячей клавише.
В подсветку синтаксиса добавил комментарии Lua "--".
Добавил восстановление иконки в трэе, при перезапуске проводника.
Слегка подправил вывод сообщений об ошибках Lua, теперь сообщает какое именно было исключение.
LuaJIT 2.0.5 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/
JIT: ON CMOV SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse
> a = 1/0
> print(a)
inf
>
--lua
a = 1/0
log(a)
вывод:
Lua error.
Floating point division by zero
Слабая причина - либо источник передача стрингом его в этом случае не устраивает.
Ставлю на то, что либа скомпилена не та версия/не те ключи/особенности компилятора.
Заменил либу на компиленную в студии, получил:
could not load Lua library "lua5.1.dll".
А ты бету или стабильную в пилот встраивал? Стабильная - это 5.1. Бета строится вокруг 5.2. В 5.2 вроде какие-то изменения с делением на ноль.
Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)