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

Darkar25

Пользователи
  • Публикации

    39
  • Зарегистрирован

  • Посещение

  • Победитель дней

    2

Сообщения, опубликованные пользователем Darkar25


  1. Решил возобновить разработку спустя год)
    Добавил веб интерфейс для управления машинами, сделал source генератор для компонентов, переписал некоторые методы в компонентах с туплов на OneOf, чутка поменял расположение некоторых файлов в проекте, пофиксил некоторые косяки в компонентах которые не заметил при написании компонентов...
    Первое сообщение в теме обновил доп.инструкциями для новых фишек


  2. Пофиксил геоанализатор, Добавил недостающие проверки в классе агента, Добавил метод для получения направления взгляда робота без улучшения "Навигация"...

    UPD спустя 4 часа:

    Нашел на форуме парочку очень интересных тем: фильтрация шума геоанализатора и вычисление константы шума геоанализатора...добавил соответствующие методы в код сервера :)

    Тема с фильтрацией шума

    Тема с получением шумовой константы

    UPD спустя 2 часа:

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

    • Нравится 2

  3. 2 часа назад, num_pi сказал:

    Ты имеешь ввиду, что, что бы отправить данные формат которых это таблица, её надо конвертировать в строку? И спрашиваешь как это сделать, лучшим образом, я правильно понимаю?

    Верно. есть в луа таблица (table) и её надо в какой-нибудь формат перевести чтобы можно было перегнать с машины(компьютер/робот в майнкрафте) по сокету на сервер и там прочитать данные...на данный момент я эту проблему решил выдернув json енкодер с гитхаба и переделав его под свои нужды...если есть решение получше то хотелось бы его зачитать и возможно применить в этом проекте...


  4. @num_pi, порылся в инете и выяснил что луа из коробки не умеет конвертировать таблицы в строки (ну разве что table.concat или string.pack, но они подходят только для очень простых случаев, а для передачи например информации о результате сканирования геоанализатором нужно передавать таблицу полностью, вместе с подтаблицами)...и учитывая что на шарпе нет адекватных парсеров луа таблиц подходящих под методы конвертации рекомендуемые в интернете то за неимением альтернатив - json остаётся основным способом передачи данных с машины на сервер...чутка енкодер на клиенте покромсал(теперь он по кол-ву строк даже меньше основного кода клиента), использовал более правильные техники работы с таблицами и конкатенации строк и по идее он стал побыстрее чем до этого...
    Но если есть предложения как всё-таки избавить клиент от необходимости как-то обрабатывать таблицы лишний раз перед отправкой то буду рад выслушать :)


  5. Добавил глобальное кэширование и методы для получения уровня некоторых компонентов

    UPD спустя 7 часов:

    Пофиксил смешивание пакетов (это всетаки был серверный косяк а не клиентский) и теперь можно спокойно зашвыривать машину пакетами и ничего от этого не будет :D

    Добавил поддержку Inf и NaN на приём от машины

    Сделал метод Invoke чуть более умным, теперь не нужно экранировать строки при подаче их в этот метод, он сделает это сам...так-же добавил пачку захардкоженных типов переменных для преобразования...

    Добавил алиасы для енума Sides, отключаются директивой предпродессора OpenOS


  6. По просьбе @ECS добавил метод GetComponents() для получения списка компонентов асинхронно...

    Так-же добавил(хотя лучше сказать тупо скопипастил с вики опенкомпов) в код документацию, правда пока что только для компонентов...

    • Нравится 1

  7. 3 минуты назад, num_pi сказал:

    если избавится от json и на клиенты слать сразу lua table, можно увеличить скорость обработки данных в разы.

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


  8. 3 часа назад, ECS сказал:

    или как минимум текстовые summary с пояснением, что вот этот метод асинхронен, а этот нет:

    summary я напишу везде, оно у меня в планах уже есть...summary бывают довольно полезны когда непонятно что вообще за метод в чужом коде и надо по-быстрому разобраться...просто навёл мышку и вот тебе пояснения...


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

    А список запрашивается часом не синхронно? Что произойдёт, если, к примеру, я в мгновение обращусь к свойству machine.Components у 50 подключённых машин? Заблокируется ли серверный поток вплоть до получения всех списков? Если да, то было бы неплохо получать компоненты через await machine.GetComponents() без фризов

    Запрашивается синхронно..идея с методом хорошая, обязательно добавлю)

     

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

    Вообще согласен, особенно если сервер не имеет синхронных методов - в этом случае суффиксы Async бессмысленны. Но тут он имеет!11

    Ну по факту из синхронных аналогов методов там только свойства, половину из которых юзать вообще ни разу не хорошая идея и лучше вообще выключить в свойствах проекта)))

    Ну вообщем окей, может быть протыкаю Async на всех методах в будущем...

    • Нравится 1

  10. 9 минут назад, ECS сказал:

    А в целом было бы очень клёво иметь нейминг по конвенциям майков или как минимум текстовые summary с пояснением, что вот этот метод асинхронен, а этот нет

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


  11. 28 минут назад, ECS сказал:

    почему некоторые методы машины синхронны (components.TryGet), а другие асинхронны (gpu.Bind), если и тот, и другой выполняются на одной синхронной машине? В случае с Bind я асинхронно ожидаю результат привязки, это логично. А почему тогда список компонентов возвращается синхронно?

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


  12. Что такое RemoteOS

    RemoteOS - это мост для связи OpenComputers с внешним миром, написанный на языке C# (.NET 6.0).

    В чём отличие RemoteOS от уже существующих решений

    • Начнём с самого очевидного и главного - на сервере имеется (почти) точная копия API OpenComputers. Это позволяет не только использовать подсказки в коде при работе с мостом в IDE но и проверять данные подаваемые в методы ещё до отправки их на компьютер OpenComputers(далее машина). Так-же такой подход позволяет реализовать кэширование, которое даёт возможность в некоторых местах не дёргать постоянно машину для опроса актуальных значений...
    • Из-за того что на сервере наклёпано столько архитектуры он не такой легковесный как остальные мосты...
    • Мой мост работает не из под OpenOS а прямо с EEPROM'а, что позволяет значительно снизить минимальные системные требования для работы этого моста но при этом это же отличие значительно его ограничивает - будут недоступны все те удобненькие библиотеки из опенос, то-есть нельзя работать ни с чем кроме того что предоставляет lua и клиентская ос моста...
    • Не нужно запрашивать сигналы с машины, она сама их шлёт серверу...

    Какие у RemoteOS системные требования

    Для машины - интернет карта и EEPROM прошитый на клиентскую ос RemoteOS

    Скрытый текст

    Компьютер:Screenshot_1220.png.da75482f563746bbe26de2e244ba50c3.png (Компьютеры могут иметь интернет-платы только со 2 уровня)

    Микроконтроллер: Screenshot_1197.png.d0e4bf676f006e469592a510eafc3f96.png (Микроконтроллеры могут иметь интернет-платы только со 2 уровня)

    Дрон: Screenshot_1203.png.9688b7026f9e45ae4444e68db8af2a93.png

    Планшет: Screenshot_1211.png.6bdaeea8a5b6c6dfea92139c09754f91.png

    Для сервера - 1 открытый сетевой порт чтобы иметь связь с машиной и достаточная вычислительная мощность чтобы суметь запуститься а затем отсылать пакеты машинам, получать от них ответ и обрабатывать этот ответ...

    Как же всё таки пользоваться RemoteOS

    Начнём с того что C# - не самый удачный выбор для связки с LUA ибо C# это строго типизированный яп а луа не очень...и подгонять сервер под все причуды луа кода было тем ещё приключением...но у меня вроде как вышло, так что посмотрим как всем этим добром пользоваться...

    Ловля подключений:

    Скрытый текст

    Самый простой сервер выглядит как-то вот так...

    
    var server = new RemoteOSServer(IPAddress.Any, 4466);
    server.onConnected += async (Machine machine) => {
      //machine - наша только что подключившаяся машина, большинство дальнейших туториалов будут подразумевать что вы пишете код внутри этого блока
    };
    server.Start();
    Console.WriteLine("Server started");
    while(true) Thread.Sleep(0);

     

    Компоненты:

    Скрытый текст

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

    
    var components = await machine.GetComponents();

    Список компонентов содержит несколько основных методов для работы с списком компонентов...

    
    components.IsAvailable<RobotComponent>() //Проверяет, есть ли такой компонент в машине
    components.List<ScreenComponent>() //Получает список всех компонентов указанного типа
    components.GetPrimary<Printer3DComponent>() //Получает компонент указанного типа, если такого компонента нет возвращает null
    components.TryGet<KeyboardComponent>(out var keyboard) //Расширение RemoteOS, добавляющее Try метод для получения компонентов - это как IsAvailable и GetPrimary в одном методе

    После того как компонент получен, можно использовать его функционал, например привязать экран к видеокарте и написать какой-нибудь текст

    
    if(components.TryGet<ScreenComponent>(out var screen) && components.TryGet<GraphicsCardComponent>(out var gpu))
    {
    	if(await gpu.Bind(screen))
        	{
    		await gpu.Set(1, 1, "Hello from RemoteOS!");
        	}
    }

    Все методы всех компонентов я тут перечислять не буду иначе пост будет занимать 3 километра чистого текста :)
    Лучше сами разверните сервер и потыкайтесь...

    Следующие компоненты НЕ ПОДДЕРЖИВАЮТСЯ в RemoteOS:

    1. Debug карта (реализация довольно сложная, решил забить)
    2. Редстоун карты
    3. Улучшение торговли
    4. Интернет карта (зачем интернет на машине если есть интернет на сервере)
    5. Дата-карта 3 уровня (зачем криптография на машине если есть криптография на сервере)

    Но вы всегда можете либо добить совместимость существующих компонентов либо добавить свои собственные...вот пример тестового компонента:

    
    [Component("test")] //в кавычках пишется имя компонента в OpenComputers, если этого аттрибута нет то компонент не будет обрабатываться сервером - это может быть полезно для налседования компонентов
    public partial class MyComponent : Component //Необходимо наследоваться от Component
    {
    	public MyComponent(Machine parent, Guid address) : base(parent, address)
    	{
    	}
    
      	public async Task MySetter(int somevalue, string val) => await Invoke("setSomething", somevalue, val); //вызываем метод Invoke чтобы запустить метод на машине от имени этого компонента
    	
      	public async Task<int> MyGetter() => (await Invoke("getSomething"))[0];
      
      	// С недавних пор компоненты поддерживают автоматическое вычисление имени метода для вызова на машине
      	// Для этого используется метод GetInvoker который возвращает делегат, в который можно передать все необходимые аргументы метода.
      	public async Task MyInvokerMethod(int somevalue, string val) => await GetInvoker()(somevalue, val); // Вызовет метод myInvokerMethod на машине
    
    	// Так-же можно не реализовывать метод самому и предоставить это генератору
    	// Сгенерированный метод будет просто вызывать соответствующий метод на удалённой машине.
    	public partial Task<string> PartialCall(); // Сгенерированный код: => (await GetInvoker()())[0];
    
    	// Для методов без результата генератор не будет использовать async/await
    	// Аргументы тоже поддерживаются генератором
    	public partial Task AnotherPartialCall(string somevalue); // Сгенерированный код: => GetInvoker()(somevalue);
    }

    Следующие компоненты поддерживаются, но НЕ РЕКОМЕНДУЮТСЯ:

    1. Компонент базы данных (лучше хранить информацию о предметах на сервере)
    2. Дата-карты 1 и 2 уровня (весь функционал этих карт отлично выполняется и на сервере, входные данные не проверяются на правильность)
    3. Диски (лучше хранить все свои файлы на сервере, как минимум потому что на сервере намного больше места)
    4. EEPROM (по той-же причине что и 3 пункт)
    5. Файловые системы (по той-же причине что и 3 пункт)

     

    Сигналы:

    Скрытый текст

    Несмотря на то, что pullSignal и pushSignal полностью поддерживаются в RemoteOS их крайне не рекомендуется использовать...вместо этого лучше работать с сигналами на сервере без лишнего дёргания машины...вот парочка примеров:

    
    //Компоненты могут реализовывать свои ивенты на которые можно подписаться и слушать всякие интересные штуки...вот например нажатия на клавиши на клавиатуре на машине
    if ((await machine.GetComponents()).TryGet<KeyboardComponent>(out var keyboard))
    {
    	keyboard.KeyDown += async (c, key, player) => //Конкретно этот ивент передает char, код клавиши и имя игрока нажавшего клавишу...компоненты могут реализовывать свои ивенты со своими наборами данных
    	{
    		Console.WriteLine($"{player} нажал кнопку '{c}' ({key})");
    	};
    }
    //Можно использовать и более низкоуровневый способ слушать ивенты
    machine.Listen("inventory_changed", (parameters) => {
    	Console.WriteLine("У робота поменялся инвентарь в слоте: " + parameters[0]);
    });
    //Так-же можно отсылать и принимать кастомные сигналы
    machine.Listen("remoteos_test", (data) => {
    	Console.WriteLine("Тестовый сигнал с данными: " + string.Join(",", data.Linq.Select(x => x.Value)));
    });
    machine.FireSignal("remoteos_test", 1, 234, "asd", true); //Да, можно и через machine.Computer.PushSignal("remoteos_test", 1, 234, "asd", true) но зачем...так же намного шустрее реагирует...

     

    Выполнение произвольного кода:

    Скрытый текст

    Тут тоже ничего трудного нет, просто используем Execute или RawExecute

    
    machine.Execute("computer.beep(1000, 1)"); //Выполнится код return json.encode({computer.beep(1000, 1)})
    machine.RawExecute("computer.beep(1000, 1)"); //То-же самое что и метод выше но без обёртки в json.encode и без return

     

    Директивы предпроцессора:

    Скрытый текст

    Проект RemoteOS содержит несколько настраиваемых переменных

    ROS_PROPERTIES - Добавляются свойства для повышения читабельности вашего кода

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

    ROS_GLOBAL_CACHING - Сервер использует глобальное кэширование для снижения количества вызовов методов на машине, сохраняя некоторые свойства компонентов для восстановления этих свойств при обращении к ним на компонентах того-же типа

    OpenOS - Добавляются расширения для компонентов аналогичные расширениям OpenOS

    В файле Helpers/OpenOS.cs в самом начале файла так-же можно настроить конкретные категории расширений

    В файле Helpers/RemoteOSExtensions.cs в самом начале файла можно настроить категории расширений от RemoteOS

     

    Веб сервер:

    Скрытый текст

    На данный момент веб сервер имеет довольно скудный функционал - только бегать роботами по карте и сканировать всё вокруг.
    На сайте имеется Waila, дебаг информация (F4), полноценный рендер блоков.

    Для начала работы с сайтом нужно запустить веб сервер и подключить к нему одного или более роботов/компьютеров/дронов(тестировалось только на роботах, но в теории должно работать исправно и с остальными типами машин).
    После того как робот подключился к серверу он появится в списке машин слева сверху и будет иметь один из нескольких статусов:
    OFFLINE - машина оффлайн, управлять ей сейчас нельзя. в этом статусе можно только изменять координаты машины.
    AWAITING POSITION - эта машина впервые подключилась к серверу и необходимо установить координаты нажав на эту кнопку
    READY - машина онлайн и готова к управлению. при нажатии на эту кнопку машина перейдёт в статус SELECTED
    SELECTED - текущая выделенная машина которой вы сейчас управляете
    После того как вы выбрали робота вы можете управлять им используя кнопки WASD, Shift(опуститься вниз), Space(подняться наверх).

    Управление камерой:
    ЛКМ - Вращать камеру
    ПКМ - Перемещать камеру
    СКМ - Приблизить/Отдалить

    На сайте установлены такие "моды" как minecraft, opencomputers, wailaharvestability, remoteos(модельки для роботов и дронов). чтобы установить дополнительные моды необходимо закинуть в папку wwwroot/assets необходимые ассеты(текстуры, модели, файлы локализации). я постарался сделать так, чтобы сайт требовал минимального вмешательства в ассеты для установки, но к сожалению иногда приходится делать мапперы для файлов локализаций и менять модели чтобы они корректно загружались на сайте.

    Скриншот сайта:
    Screenshot-1636.png


    Какие у меня планы на RemoteOS

    • [+] Планирую добавить документацию в код, чтобы можно было прямо в IDE зачитать что конкретный метод делает...
    • [+] Хочу сделать веб-интерфейс для управления машинами
    • Хочу довести кэширование до ума, чтобы надо было дёргать машины ещё меньше
    • Может быть добавлю поддержку локальной(внутриигровой) сети на сетевых картах/ретрансляторах чтобы ещё больше снизить минимальные требования для клиентской ос

    Ссылки

    Репозиторий проекта: Тык (Github)

    Клиентская ОС: Тык (Github)

    Демо-видео: Тык (Яндекс диск)

    • Нравится 6

  13.  

    Какой-то несвязный поток мыслей. Отвечу на вопрос, который я понял.

    1. Создаём на дискете файл .prop, туда пишем {label = "MineOS"} или {label = "MineOS", reboot = true}, если нужно ребутаться.
    2. Создаём на дискете файл .install, туда пишем os.execute("pastebin run 0nm5b1ju").
    3. Та-дам.

     

    спасибо...помог..


  14. вот в чем вопрос: как сделать дискету установочным диском?к примеру закинул ты туда установщик MineOS(0nm5b1ju) и хочешь чтобы на другом компе при написании в shell Install запускался установщик MineOS.как это можно реализовать?

     

    т.к при написании pastebin run 0nm5b1ju докачиваются дополнительные файлы то нужно чтобы запускался не установщик а выполнялась команда(в нашем случае pastebin run 0nm5b1ju) и как сделать так чтобы при открывании какого либо файла в формате lua в shell посылалась команда?


  15. т.к. в кодинге на луа я больше рак чем 5 крабов вместе взятых попрошу у вас помощи написать мне прогу для отладочной карты(представим у меня есть такая плата и она у меня вшита в планшет)...как можно сделать так чтобы при нажатии определенных кнопок происходило соотвествующее им десвие(к примеру нажал G и выполнилась команда setGameType(value: string) с которой я сам еще не разобрался...или при нажатии 1 выполнялась команда getposition() number, number, number и запоминались координаты потом при нажатии 2 также запоминались вторые координаты(как выделение в WE) и потом при нажатии S выводилось окно в которое надо написать айди блока который при нажатии enter сетнется как в WE) и так далее...и если такая программа есть то подскажите её и не мучайте себя))если же нет то помогите склепать

    • Нравится 1

  16. я модернезировал прогу для управления роботом с планшета...и в связи с недавними изменениями(добавлением возможности копать перед роботом и возможностью копать в 3 стороны(вперед наверх и вниз))после отправки команды роботу он выполняет её дважды
    помогите пж...
    ПЛАНШЕТ - https://pastebin.com/cMcYEQAW
    РОБОТ - https://pastebin.com/4mDUTWKN


  17. Просто куда-то затерялась переменная 'slot', если ее вернуть, то никаких ошибок. А нужные функции, без проблем добавляются в таблицу 'commands'.

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


  18. local component = require("component")
    local robot = require("robot")
    local event = require("event")
    local port = 512
    local modem
    
    if component.isAvailable("modem") then
      modem = component.modem
    else
      error("Этой программе требуется беспроводной модем для работы!")
    end
    
    modem.open(port)
    
    local commands = {
      forward = robot.forward,
      back = robot.back,
      turnRight = robot.turnRight,
      turnLeft = robot.turnLeft,
      up = robot.up,
      down = robot.down,
      suck = robot.suck,
      drop = function() -- создаем функцию дропа
        robot.drop() -- дропаем предмет вперед
        slot = (slot + 1)%robot.inventorySize() -- задаем номер следующего
        if slot == 0 then -- проверяем исключение
          slot = 1 -- назначаем, в случае исключения
        end
        robot.select(slot) -- выбираем 
      end,
    }
    
    local function receive()
      while true do
        local e = {event.pull('modem_message')}
        if commands[e[7]] then -- если в списке есть такая команда
          commands[e[7]]() -- выполнить
        end
      end
    end
    
    receive()
    

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

    https://yadi.sk/i/ZuC6cYkm3KDHrJ


  19. заменить 'cmd' на 'commands' в строках 59, 60 и удалить все с 61 до 87

    ну и поправить event.pull() на event.pull('modem_message')

    а...зачем собсна удалять такую тучу строк?ну...я особо не разбираюсь но наверно это много функций порежет...

×
×
  • Создать...