Перейти к содержанию
RedTeapot

redMacros - еще один макро-мод для кубача

Рекомендуемые сообщения

redMacros - да, еще один макро-мод для Minecraft.

 

В общем, надоел мне этот ваш MKB, и я психанул. Начал пилить свои макросы с событиями и скриптами.

 

TL; DR: Пока качать нечего, ибо все еще крайне сырое. А еще я не могу обещать, что я смогу допилить его. Как всегда.

 

В качестве скриптового языка я выбрал Lua - достаточно популярный, простой (= примитивный) и в то же время шустрый интерпретируемый язык программирования. Используется, например, в ComputerCraft, Garry's Mod, Don't Starve.

 

Конечно, я не стал писать свой интерпретатор. Вместо этого я использовал luaj - инерпретатор Lua, написанный полностью на Java.

 

Поскольку я не могу сразу выкатить все в кошерном виде, пока систему макросов решил реализовать примерно так:

 

При загрузке мира/подключении сервера в папке .minecraft/liteconfig/common/redMacros/macros ищется файл с именем, сформированным по специальному шаблону и содержащим имя мира или адрес сервера. Если таковой имеется - он выполняется. То есть, да, скрипты запускаются сразу после загрузки мира.

 

Понятно, что в таком виде оно никому нафиг не нужно. Поэтому я собираюсь реализовать систему событий. И этот макро-скрипт, помимо всего прочего, сможет просто подписываться на какие-либо события: нажатия клавиш, вход/выход из игры (другого игрока, да), всякие там чатики, голоды и прочие. Ну и примерно таким же макаром планирую реализовать чат-фильтры и прочие плюхи.

 

Пока я это рассматриваю как временную меру. Хотя чем-то мне такой подход даже начинает нравиться - как-никак, дает очень большую гибкость. Посмотрим, что выйдет.

 

А исходники есть (ну, или будут) на GitHub: https://github.com/Red-Teapot/redmacros

Лицензия - MIT.

 

Еще раз повторюсь: я не обещаю, что смогу довести дело до конца, но очень надеюсь, что таки смогу. "Чайник, который смог", ага.

Изменено пользователем RedTeapot
  • Плюс 4

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Было бы здорово, если непосредственные пользователи MKB примут участие в разработке проекта = заодно и программированию поучитесь )))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 минут назад, Admin сказал:

Было бы здорово, если непосредственные пользователи MKB примут участие в разработке проекта = заодно и программированию поучитесь )))

 

Ну, на то оно и opensource. А вообще, наверное, проще будет сначала показать, что я придумал, а потом смотреть, удобно оно или нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ага - сделай какой-нибудь простейший минимум + выкладывай сразу на всякие буккиты и т.д. = сразу пойдут отклики и будет понятно - стоит ли работать дальше.
С нас помощь по продвижению и развитию )))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, newoldmax сказал:

Нужны примеры

 

Поскольку пока нет вообще ничего готового, могу только привести сферический пример в вакууме.

 

Допустим, хотим мы в мире под названием "Some singleplayer" играть с макросами. Тогда нам нужно в папке .minecraft/liteconfig/common/redMacros/macros создать файл с названием "sp.Some singleplayer.lua" - это и будет файл нашего скрипта. Выполняться он будет при входе в этот мир.

 

Допустим, что мы хотим делать что-то, когда игрок голоден. Тогда код должен быть примерно вот таким:

local function onHungerChange(hunger) -- Hunger change listener function
    print 'Чувак, пожри чего-нибудь'
    print 'А хотя не, я сам'
    
    for i = 1, 9 do
        if player.getItemAtHotbar(i):isEdible() then
            player.selectHotbar(i)
            player.useFor(10 * 20) -- 200 ticks = 10 seconds
        end
    end
end

events.addListener('player.hunger.change', onHungerChange) -- Subscribe to hunger change event

Думаю, выглядеть это будет примерно вот так. Зато доступны всякие штуки типа require - можно включать в скрипт сторонние файлы (например, вынести что-нибудь во внешний файл). Ну и искаропки luaj много чего умеет.

 

В общем, я попробую побыстрее сделать что-то более-менее работающее, чтобы можно было посмотреть на деле, каково это.

 

================================================

 

Итак, наконец-то я реализовал систему событий. Надеюсь, дальше будет быстрее :D

 

Например, вот это уже работает (да, вызывает цепную реакцию и адовый пипец, поскольку в обработчике события об отправленном в чат сообщении отправляется еще одно - специально так сделал для проверки):

print 'SP test world'

local function listener()
    print 'Listener test run'
end

events.addListener('test_event', listener)

print 'Added test listener'

events.enqueue('test_event', {})

print 'Enqueued test event'

local function chatListener(params)
    print('Sent chat message:', params.message)
    chat.send('eeee pipets')
end

events.addListener('chat.messageSent', chatListener)

print 'Added chat listener'

Надо теперь API-шечек напилить, чтоб можно было не только чат ломать.

 

P. S. Почему-то я захотел отметить, что оно умеет в русский. Не знаю, почему мне захотелось это сделать.

Изменено пользователем RedTeapot
  • Плюс 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Итак, допилил систему событий (ага, все оказалось гораздо сложнее, чем ожидалось). Реализовал библиотеку событий и чата.

 

Теперь можно нормально подписываться на события и отправлять их, флудить в чат, устанавливать фильтры на входящие и исходящие сообщения чата. Хотя из-за специфики работы сервера, отправленные мною сообщения попадают в фильтр входящих у меня. Мопед не мой, виноват сервер.

 

А еще начал писать Вики: https://github.com/Red-Teapot/redmacros/wiki

 

===========================================

 

Кажется, redMacro перешел границу абсолютной бесполезности: на нем уже можно реализовать фильтр чата и небольшую плюшку, чтоб было удобнее отвечать на ЛС в Майне.

 

Примерно так:

 

Спойлер

-- This is used to remember last PM received message author nickname
local lastPMNickname = nil

local function inboundChatFilter(msgClean, msgRaw)
  -- Current received message author nickname
  local nickname = nil
  
  -- Current received message text
  local text = nil
  
  -- Regular messages
  nickname, text = msgClean:match('^<([_%w]+)> (.*)$')
  if nickname ~= nil and text ~= nil then
    print('§r§l' .. nickname .. ': §r' .. text)
    return false
  end
  
  -- Messages from Dynmap
  nickname, text = msgClean:match('^%[WEB%] ([_%w]+): (.*)$')
  if nickname ~= nil and text ~= nil then
    print('§r§2§l' .. nickname .. ': §r' .. text)
    return false
  end
  
  -- PM messages
  -- Pattern is more complicated because of clans and guilds on BByaWorld
  nickname, text = msgClean:match('^.- ?([_%w]+) ?[%u %|%-]* шепчет вам: (.+)$')
  if nickname ~= nil and text ~= nil then
    print('§r§b§l§n' .. nickname .. '§r§l: ' .. text)
    lastPMNickname = nickname
    return false
  end
  
  -- Everything else
  return {true, '  ' .. msgRaw}
end

local function outboundChatFilter(message)
  answer = message:match('^/ans ?(.*)$')
  
  if answer ~= nil then
    if lastPMNickname ~= nil then
      chat.send('/tell ' .. lastPMNickname .. ' ' .. answer)
    end
    
    return false
  end
  
  return true
end

chat.setInboundFilter(inboundChatFilter)
chat.setOutboundFilter(outboundChatFilter)

 

Этот чат-фильтр позволяет полностью поменять отображение чата и добавляет "команду" /ans, которая позволяет ответить на последнее ЛС.

Изменено пользователем RedTeapot
  • Плюс 2

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 часов назад, RedTeapot сказал:

Этот чат-фильтр позволяет полностью поменять отображение чата и добавляет "команду" /ans, которая позволяет ответить на последнее ЛС

Припас идею, напишу себе на МКБ. Все 1 лайк в день на тебя уходит.

Аудитория русскоязычная, а пишешь всё на заокеанском, изверг.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Достижения

7 часов назад, OcelotJungle сказал:

Аудитория русскоязычная, а пишешь всё на заокеанском, изверг.

 

Лень переключать раскладку. Ну и не факт, что таки русскоязычная - я думаю податься на minecraftforum, когда будет с чем.

 

6 часов назад, Admin сказал:

А чего всё на английском, а "шепчет вам" - на русском? :)

 

Lua есть Lua, это не 1С. Комментарии на ынглише потому, что мне просто лень переключать раскладку. Да и не привык комментарии в коде по-русски писать - моветон. А "шепчет вам" по-русски тут из-за того, что это часть шаблона сообщения: по этой подстроке можно отделить никнейм игрока от текста сообщения.

 

Хотя вообще, пока писал эту штуку, я понял, что с фильтрами чата что-то не так: неудобно и криво. Надо решить, как это переделать.

 

Например, сейчас чат-фильтр ломает всякое хитрое форматирование (события по клику, например), даже если сообщение прошло его без изменений. И прикол в том, что внутри игры на вход подается уже готовое, по сути, AST, содержащее узлы, у которых заданы всякие там параметры. Возможно, надо это AST передавать как раз на вход чат-фильтра. Ну и ждать, что чат-фильтр выдаст такое же AST на выход. С другой стороны, я не знаю, сильно ли это все усложнит.

 

Можно от чат-фильтра ждать только boolean - если true, то сообщение прошло без изменений, а если false - то вообще не прошло (пишите сами через свой print, да).

 

В общем, думать надо еще много.

Изменено пользователем RedTeapot

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 часов назад, RedTeapot сказал:

Лень переключать раскладку. Ну и не факт, что таки русскоязычная - я думаю податься на minecraftforum, когда будет с чем.

 

А вики?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Достижения

15 минут назад, OcelotJungle сказал:

А вики?

 

11 часов назад, RedTeapot сказал:

Ну и не факт, что таки русскоязычная - я думаю податься на minecraftforum, когда будет с чем.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, OcelotJungle сказал:

А вики?

Помоги ему сделать руссую вики )

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 минут назад, Admin сказал:

Помоги ему сделать руссую вики )

 

 

Мне б сначала хоть сделать что-то, к чему есть смысл писать вики :D

 

=====================================

 

Тем временем, я опять упоролся. Встречайте, фильтр чата на 195 строк кода!

 

Спойлер

local lastPMNickname = nil

local function getOrdinaryPlayerMessage(nickname, text)
    return {
        type = 'textComponent',
        siblings = {
            {
                type = 'textComponent',
                text = nickname,
                style = {
                    color = 15,
                    bold = true
                }
            },
            ': ',
            {
                type = 'textComponent',
                text = text,
                style = {
                    color = 15
                }
            }
        }
    }
end

local function getDynmapPlayerMessage(nickname, text)
    return {
        type = 'textComponent',
        siblings = {
            {
                type = 'textComponent',
                text = nickname,
                style = {
                    color = 2,
                    bold = true,
                    hoverEvent = {
                        action = 'show_text',
                        value = {
                            type = 'textComponent',
                            text = 'Dynmap'
                        }
                    }
                }
            },
            ': ',
            {
                type = 'textComponent',
                text = text,
                style = {
                    color = 15
                }
            }
        }
    }
end

local function getPrivatePlayerMessage(nickname, text)
    return {
        type = 'textComponent',
        siblings = {
            {
                type = 'textComponent',
                text = nickname,
                style = {
                    color = 11,
                    bold = true,
                    insertion = nickname,
                    clickEvent = {
                        action = 'suggest_command',
                        value = '/msg ' .. nickname
                    },
                    hoverEvent = {
                        action = 'show_text',
                        value = {
                            type = 'textComponent',
                            text = 'Private message'
                        }
                    }
                }
            },
            ': ',
            {
                type = 'textComponent',
                text = text,
                style = {
                    color = 15
                }
            }
        }
    }
end

local function dumpTable(tbl, indent)
    if not indent then
        indent = 0
    end
    
    for k, v in pairs(tbl) do
        local template = '§5' .. string.rep('  ', indent) .. tostring(k) .. ': '
        if type(v) == 'table' then
            print(template)
            dumpTable(v, indent + 1)
        elseif type(v) == 'string' then
            print(template .. '\'' .. tostring(v) .. '\'')
        else
            print(template .. tostring(v))
        end
    end
end

local function checkOrdinaryPlayerMessage(message)
    if message.type ~= 'textComponent' then return false end
    if not message.siblings then return false end
    if #message.siblings ~= 1 then return false end
    if message.siblings[1].type ~= 'textComponent' then return false end
    
    local nickname = nil
    local text = nil
    
    nickname, text = message.siblings[1].text:match('^<([_%w]+)> (.*)$')
    
    if not nickname or not text then return false end
    
    return getOrdinaryPlayerMessage(nickname, text)
end

local function checkDynmapPlayerMessage(message)
    if message.type ~= 'textComponent' then return false end
    if not message.siblings then return false end
    if #message.siblings ~= 2 then return false end
    if message.siblings[1].type ~= 'textComponent' then return false end
    if message.siblings[2].type ~= 'textComponent' then return false end
    
    local nickname = message.siblings[1].text:match('^%[WEB%] ([_%w]+): $')
    local text = message.siblings[2].text
    
    if not nickname or not text then return false end
    
    return getDynmapPlayerMessage(nickname, text)
end

local function checkPrivatePlayerMessage(message)
    if message.type ~= 'translatableComponent' then return false end
    if message.key ~= 'commands.message.display.incoming' then return false end
    
    local nickname = message.args[1].style.insertion
    local text = ''
        
    for i = 1, #message.args[2].siblings do
        text = text .. message.args[2].siblings[i].text
    end
    
    lastPMNickname = nickname
    
    return getPrivatePlayerMessage(nickname, text)
end

local function inboundChatFilter(message)
    local res = false
    
    res = checkOrdinaryPlayerMessage(message)
    if res then return res end
    
    res = checkDynmapPlayerMessage(message)
    if res then return res end
    
    res = checkPrivatePlayerMessage(message)
    if res then return res end
    
    return {
        type = 'textComponent',
        text = '  ',
        siblings = {
            message
        }
    }
end

local function outboundChatFilter(message)
    local answer = message:match('^/ans ?(.*)$')
    
    if answer ~= nil then
        if lastPMNickname then
            chat.send('/msg ' .. lastPMNickname .. ' ' .. answer)
        end
        
        return false
    end
    
    return true
end

chat.setInboundFilter(inboundChatFilter)
chat.setOutboundFilter(outboundChatFilter)

 

 

Собсна, плюхи те же, но теперь я работаю с компонентами текста - внутриигровым представлением всего текста в чате. Не знаю, что лучше: оставить все, как оно сейчас (штука очень гибкая, но вот такие простыни порой порождает) или же вернуться к примитивным регуляркам.

 

Вернуться к примитивным регуляркам = использовать только значок параграфа для форматирования при выводе текста, ну и сами сообщения в чате парсить только регулярками (с форматированием или без).

 

Оставить все как есть = получить очень могучую систему, но она порождает кучу кода (в первую очередь, из-за таблиц как в приведенных выше функциях а-ля getPrivatePlayerMessage). Эта "могучая система" могет делать всякие штуки при наведении и нажатии на текст, позволяет более понятно задавать форматирование (без этих значков параграфа) - по сути, аналог команды /tellraw (ибо /tellraw внутри себя тоже использует компоненты текста, но парсит их из JSON, переданного команде).

 

В общем, любители MKB, хочется послушать ваши мнения.

Изменено пользователем RedTeapot

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Второй вариант - жсон какой-то (больно слова знакомые), но, в общем, читаемо, если вдуматься. Я бы оставил, если у него прям такие крутые возможности. В синтаксисе разобраться без проблем можно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Достижения

21 час назад, RedTeapot сказал:

фильтр чата на 195 строк кода

При желании всякие интегрированные среды разработки (IDE) могут сворачивать все эти функции = могут быть видны только 5-10 блоков с комментами к ним = будет легко ориентироваться )

Наверняка и более простые редакторы такое умеют (с плагинами - точно) = нужно просто указать в рекомендациях - использовать специализированные редакторы, которые помогут курить гигантский код :)

 

Короче, я за крутой функционал!
Имхо, среднестатистический геймер даже MKB не осилит...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только что, Admin сказал:

При желании всякие интегрированные среды разработки (IDE) могут сворачивать все эти функции = могут быть видны только 5-10 блоков с комментами к ним = будет легко ориентироваться )

Наверняка и более простые редакторы такое умеют (с плагинами - точно) = нужно просто указать в рекомендациях - использовать специализированные редакторы, которые помогут курить гигантский код :)

 

Короче, я за крутой функционал!
Имхо, среднестатистический геймер даже MKB не осилит...

 

Я знаю про IDE и фолдинг. Просто думаю: "А не фигню ли я делаю?" Вот и все. Пытаюсь понять, не упер ли я в overengineering.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Помаленьку тыкаю палочкой в мод.

 

Подумал перейти на использование Forge, начал писать форджевую версию мода. Хз, как это скажется в будущем (все-таки, поддержку миксинов мне запилить не удалось), но пока все весело и радужно (так как у Форджа есть event bus, на которой у многих событий можно менять данные/отменять сами события).

 

Наверное, пытаться сделать все идеально сразу не буду, а просто в коде буду растыкивать TODO в надежде на то, что когда-нибудь допилю. Ну и пока забью на документацию, ибо нафиг надо.

 

Пока готов кусок библиотеки работы с чатом и базовая система событий. Работает все очень криво и нестабильно - опечатка в коде макроса может уронить игру.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 часов назад, RedTeapot сказал:

Помаленьку тыкаю палочкой в мод.

Если шевелится - пока всё хорошо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Достижения

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×