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

ECS

Гуру
  • Публикации

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

  • Посещение

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

    203

Все публикации пользователя ECS

  1. Новичковая, ага. Как человек, несколько лет использующий гит по цыганскому принципу "версионной файлопомойки", открыл линк ради общего развития - надо же когда-то начинать! Ни пояснения терминологии (что вообще такое репозиторий, коммит, индексация, ветки, мерж конфликты?), ни реальных примеров, ради которых осуществляется <действие> - тупо конспект для зазубривания вместо практического обучения. На пункте ниже закрыл статью как "нечитабельную". Что за теги, откуда они взялись? Для чего они? Я вижу, что "для использования в будущем", но почему мне нужно знать о них именно сейчас? Гении, блин, с 10к IQ статью писали. В чем отличие тегов от имён веток? Можно ли назначить несколько тегов одной ветке? Зачем? А ведь мы ещё даже rebase не дошли
  2. Это не позволит сделать tunnel.send() на клиенте и сдохнет с ошибкой "packet too big". Разбивать нужно самому, конечно, т.к. взаимодействие с серваком находится на сетевом уровне модели OSI. Пакетная передача, шифрование, туннелирование и т.п. - это всё же чутка иная задача, обычно перекладываемая на библиотеки, и в 99% случаев не возникающая у "программ новичков" Если всё же требуется гарантированная стойкость своей личной сети, чтобы сервер также учитывал размеры входящих пакетов, то изменить прошивку не составит труда: local maxPacketSize = 8192 ... -- 8 extra bytes for safety local packetSize = 8 for i = 6, #e do -- Two bytes overhead for each value packetSize = packetSize + tostring(e[6]):len() + 2 end -- Everything is ok, packet size is within the limits if packetSize <= maxPacketSize then -- Linked card with target channel is connected to this computer if tunnelChannels[e[6]] then tunnelChannels[e[6]].send(tunnelAddresses[e[2]].getChannel(), table.unpack(e, 7)) -- Notify other network server to search the target linked card else modem.broadcast(modemPort, "r", e[6], tunnelAddresses[e[2]].getChannel(), table.unpack(e, 7)) end -- Do something when packet size is beyond limits else tunnelAddresses[e[2]].send("packet is too big, server limit is " .. maxPacketSize) end В результате отправитель получит: Могу вставить эту фичу в сырцы, не вопрос
  3. Да, принцип схож. Однако эта схема локальна и служит для обмена сообщениями среди ограниченной группы машин, да и работает на любом мусоре - были бы слоты под карты. Как следствие, никто не будет спамить широковещательными пакетами на беспроводные точки, из-за чего связь не отвалится, и проблема "дудосеров с 9 планшетами" около роутера 2 уровня просто не возникнет. Как бы выразиться поточнее... тут возникает щекотливая ситуация, когда с точки зрения интересности отыгрыша роли на IT-сервере использование OpenNet или ZN реально веселее. Также это помогает изучить нюансы работы реальных сетей на примитивном игровом уровне. А с точки зрения практичности для клана с десятком компьютеризированных электростанций/ферм в различных мирах централизованная и приватная схема надёжнее и быстрее. Имхо, пока не настанет всесерверная утопия, пока не передохнут диссиденты-дудосеры, игроки будут ориентироваться на локальные сети
  4. Проблема: мы с друзьями живём в различных измерениях или на огромном расстоянии друг от друга, из-за чего беспроводные модемы использовать невозможно. При этом нам нужна система, позволяющая отправлять приватные сообщения конкретному человеку, зная адрес получателя. Очевидным решением будет использование связанных плат, но что если нужно работать более чем с 1 получателем? Связанные платы, увы, лимитированы. Что если мы играем с GalactiCraft, имеем базу на Земле, и кровь из носу хочется контролировать добычу камня на Луне, реакторы на Марсе и ферму урана на Венере с одного компьютера? Решение: объединить множество связанных плат в кластер! Принцип работы системы проще пареной репы: каждый новый клиент, подключаемый к сети, должен предоставить 1 из 2 скрафченных связанных плат. Первую мы вставляем в кластер, а вторую - в компьютер клиента. Чтобы отослать сообщение другому клиенту кластера, нужно знать имя канала его связанной платы. Далее - дело техники: если сервер получает сообщение от связанной платы, то осуществляется поиск платы-получателя в нём же. Если плата-получатель не найдена, то сообщение перенаправляется через широковещательный пакет проводного модема всем серверам кластера, чтобы те в свою очередь попытались найти получателя. Если получатель найден - ему отсылается имя канала отправителя и само сообщение. Теперь подумаем, как лучше объединить связанные платы. Каждая плата может быть вставлена только в Tier 3 слот компьютера или сервера. Оптимальным решением для экономии пространства будет использование серверных стоек, т.к. каждый Tier 3 сервер имеет целых 2 Tier 3 слота. Поэтому каждый сервер сможет обслуживать максимум 2 клиента сети. В итоге схема расположения стоек и конфигурация серверов должна быть примерно такой: Процессор не важен, память не важна, и требования если не нулевые, то минимальные. Разумеется, каждый сервер будет работать на микропрограмме EEPROM, ибо крафтить для этого жёсткие диски было бы нецелесообразно. Берем код и прошиваем столько EEPPROM'ов, сколько требуется: https://gist.github.com/IgorTimofeev/15b75915caa93a344c2be25dac308138 После включения сервер будет доступен для взаимодействия. Как же отправить сообщение получателю? Используем функцию tunnel.send(), и первым аргументом указываем имя канала получателя. Его можно получить через tunnel.getChannel(): local tunnel = require("component").tunnel local receiver = "867a85de-ae4c-4359-b06f-0d30c5dad6f1" tunnel.send(receiver, "Привет") Это всё замечательно - но где же практический пример? Давайте запустим чат! Да простят меня боги, старые и новые, но я буду использовать MineOS, т.к. общаться через GUI мне банально удобнее. Во всех компьютерах сети создаем новое приложение, открываем файл Main.lua для редактирования: Берём исходник чата: https://gist.github.com/IgorTimofeev/724992e8641245a51cef57ac883f541f Вставляем его содержимое вместо имеющегося в Main.lua и запускаем приложение. Для отсылки сообщения необходимо ввести канал связанной платы получателя, а также отправляемый текст. Вот пример интеллектуальной беседы двух величайших умов современности: Кроме того, каждый сервер кластера поддерживает протокол для обновления прошивки по сети, а также удаленного отключения и запуска всех серверов. Для этого вам потребуется отдельный компьютер, находящийся в локальной сети с кластером. Для удобства я также накатал мини-приложение: https://gist.github.com/IgorTimofeev/0fe93bd4549aa32161b9dbbba59425e8 Подытоживая, хотелось бы отметить, что этот софт находится в разделе "программы новичков", он не преследует никаких глобальных целей и не реализует "киллер-фич", ориентируясь больше на прикладное использование. Разумеется, серверную часть можно улучшить по своему вкусу, добавив поддержку широковещательных пакетов, PING-систему и системные события по типу дисконнекта/доступности серверов, а для клинетского чата можно реализовать систему контактов и отсылку медиа-файлов. Было бы время и желание... Однако в своё время даже такой функционал неплохо сохранил нам нервы во время войн с серверной цензурой, а также экономил время, которое потребовалось для длительных полётов на разбросанные по уголкам вселенной базы. Надеюсь, для кого-нибудь эта схема будет так же полезна, как и для нас c:
  5. Ты абсолютно прав: профита никакого, кроме "пацаны красауцы эжжи, четкий вещ накодили". У нас стимулом был скорее спортивный интерес по обходу серверных ограничений, и дискорды/скайпы отходили на второй план. Хотя на RP серверах подобный "первобытный" подход скорее приветствуется и считается некой изюминкой. А в глобальной перспективе да, любая текстовая коммуникация через самописные чаты или общеизвестные IRC/ICQ/Jabber морально устарела и в разы менее эффективна
  6. Плюсую. Также можно пойти чуть дальше и реализовать кластер связанных плат, ретранслирующий сообщения от одного адресата другому (или всем сразу) без ограничения по расстоянию. Нам с товарищами пришлось прибегнуть именно к такому решению, т.к. жили мы в различных измерениях, а администрация крайне не приветствовала выражения искренней любви к их матерям. Вышел этакий квантовый чебурнет
  7. Я эту тему, оказывается, даже пролистывал в прошлом году, но не осилил, т.к. в ней также не было ни подписей к графикам, ни подробных пояснений к происходящему. У меня вообще сложилось впечатление, что вы телепатически общались, на ходу генерируя "магические константы" типа 0.0606 и понимали друг друга с полуслова хд Поэтому, собсна, и спросил про логику расчётов именно тут, в разделе "уроки", а не в "беседке". Есть урок - есть вопрос. Мало ли вы там тупиковых ветвей в исследованиях наплодили, но уж тут-то наверняка должна быть квинтэссенция объективной истины! Мне показалось, что так будет быстрее...
  8. Ни хрена себе на поверхности, в сумме я полтора часа убил на поиск лишь основной логики. А вопросы по графикам до сих пор терзают душонку... Прости, пожалуйста, что не являюсь представителем блистательной молодёжи, ухватывающей идею на лету, и столь нагло требующей ответов(99 Но за исследование ищо раз спасибо, это было занятно!
  9. Спасибо, Алексейюрич, примерно в том же ключе вы меня отправили на пересдачу хд Мне было совсем не ясно, т.к. в нити рассуждения отсутствует инфа о том, какое именно неизвестное значение мы желаем получить. Да, сделать предположение методом исключения - это не сложно. Однако не знаю, как у других, но у меня процесс додумывания смысла в готовом учебнике/уроке/гайде/статье вызывает припекание седалища А почему мы не можем записать результат? Именованные переменные ушли на забастовку? И давно ли знак равенства для функций не указывается? Я пропустил всемирный апокалипсис? А если это так, то почему он присутствовал здесь? Видимо, апокалипсис на данную запись не распространился? Какая стойкая, однако, запись, уважаю! Кроме того, в программировании (как и в физике, в отличие от математики), мы оперируем не абстрактными функциями, а фактическими формулами, т.к. всегда работаем с набором фактических данных или группой абстрактных, подчинённых фактическому правилу. Если бы твоя формула была человеком, то выглядела бы так: Спасибо, прям как в кирпиче по матанализу от Виноградовой: ща пойду почитаю следующую главу, не дочитав текущую. Гениальная многоходовочка от автора, ставлю 5/5 на литресе! Но... но... половина вопросов так и осталась без ответа. Какая часть графика указывает на плотность, а какая на расстояние? За что отвечают цвета точек? За состояние "угаданности" и "неугаданности"? Ты ж, блин, автор статьи в разделе "уроки", ты ж, блин, строил этот график, ты ж, блин, знаешь, что там за исходные данные были. Ну подпиши их, ну интересно же! А еще почему в реальной проекции и масштабе аналогичную зависимость не получится? "Скукожь" график, наплевав на масштаб - и все получится, разве нет? Фух, хоть это я угадал. А каким образом читатель должен допереть, не имея графиков и исходных данных о геосканировании, что максимальная близость RANDOM_BYTE к целому числу означает "угаданность" плотности? Гипотетически это действительно будет так, и в идеальном случае, когда геосканер вернул результат без шума, RANDOM_BYTE будет целым, т.к. переменные из формулы оказали на результат минимальное влияние. Но чёрт возьми, это ж просто предположение, а вдруг нет! *кусаю ногти* Ага, значит, догадка была близка к истине. Хотя это было вовсе не очевидно, т.к. диапазон signed byte в [-127; 127) противоречит этой очевидности. Да, глянув на код и условие по отсечению данных, у меня возникла мысль, что возвращаемое значение функции magic() может находиться в ином диапазоне, но, блин, даже в коде "ошибочный" диапазон просто игнорируется. А на графике - нет. Магия! Неужели рисовалка графиков не имеет фичи именования координатных осей для упрощения понимания? О-о-о, на сократщину можно такую дискуссию развернуть, что счетчик PK БД форума выйдет за допустимые пределы. С методикой и подходом к самостоятельному обучению и личной интерпретации я полностью согласен, однако в данной ситуации мы имеем уже завершённый материал. Материал интересный, на актуальную тему, с хорошей науч. базой и даже наличием исследований с практическим опытом - это ж золотая жила знаний, пускай и в кубаче! Но... исходные данные только у автора. Упс. Я, может быть, очень хочу "пощупать руками и понять своим языком", открыть консольку, подставить исходники в формулу, рассчитать, порадоваться, что результат изящно сходится. А не могу. Ну то есть да, конечно, я могу запустить кубач, воссоздать исследовательскую среду, понатыкать руд, поставить пайтон и матплотлиб, построить график - но чёрт побери, за меня это уже сделали! Зачем тратить столько времени на подтверждение рабочей теории? Лучше потрачу время на срач))0
  10. Спасибо за статью, прямо в шараге себя ощутил: очень интересно, но ни хрена не понятно. И очень за это стыдно. А когда мне стыдно, то ладошки сами чешутся докопаться! Ну и заодно поинтересоваться, как же эта вундервафля работает. Я даже на этом шаге "завис" на минуту. Во что мы обращаем формулу? Что мы вычисляем в итоге, где знак равенства, черт побери? Методом исключения предположу, что мы вычисляем тот самый байт, который выдал нам ГСПЧ, а логика сокращения формулы была следующая: RANDOM_BYTE = (R - H) / D / N * 128 * 33 RANDOM_BYTE = (R - H) / D / 2 * 128 * 33 RANDOM_BYTE = (R - H) / D * 2112 Ага, понятно! Теперь я провожу своё первое сканирование, передаю параметры желаемой плотности и расстояния, получаю заветный шумовой байт в дробном виде. И что мне с ним делать? Да как определить-то? Нет, я понял, что при написании статьи это было легко, но я тоже хочу определить! *злобно топаю ножкой* Что мне даёт этот срандомленный байт? Ну 15, ну 120, а что дальше? Какова именно логика определения, угадали мы плотность или нет? Вах, красота какая... у меня бабушка похожие платочки шила, очень мягкие. А что это? "Распределение вероятностей"... вероятностей чего? Если это график, то зависимость какой величины от какой тут продемонстрирована? За что отвечают синие точки, а за что оранжевые? Напрягу последнюю неатрофированную извилину и предположу, что каждый цвет отвечает за блок с определённой плотностью. Но с какой именно? Если для статьи плотность несущественна, то насчёт того, что представляют собой координатные оси, я вообще могу лишь догадываться. Ладно, хрен с ним, пропускаю этот момент. Далее идёт исходник. Ага, ну тут-то наверняка должна быть логика из предыдущего шага, по которой можно понять, "угадали мы плотность или нет": local function magic(R, H, D) return 2112 * (R - H) / D % 1 end result = magic(blocks[i_y], hardness, distance(x, i_y+elevation-1, z)) if blocks[i_y] ~= 0 and (result > 0.9998 or result < 0.00005) then ... Берем результат сканирования, вычисляем на его основе RANDOM_BYTE, берём от него дробную часть... А зачем? Откуда взялись магические константы 0.9998 и 0.00005? Что означает это сравнение? Пытаюсь перевести на человеческий: "если RANDOM_BYTE является целым или почти целым числом, то плотность блока валидна". Но почему именно так? Почему сравнение с "близостью к единице" менее точно, чем сравнение с "близостью к нулю"? Почему мы вообще анализируем дробную часть байта, который по определению является целым числом? Как она вообще отражает соответствие искомой плотности блока? Я понимаю, что у тебя были некие исходные данные, по которым это можно было легко понять, но в статье-то их нет. Сложна, оч сложна! Пытаюсь читать дальше... Якорь мне в гузно, опять зависимость *магии* от *магии*! В порядке бреда можно предположить, что ось абсцисс олицетворяет расстояние до блока, но что за что тогда отвечает ось ординат? Стопудова не за плотность блока. Вероятно, за RANDOM_BYTE? Да вроде не, нижняя точка графика в -300 и диапазон signed byte в [-127, 127) как бы намекают... или по какой-то причине график построен в ином масштабе. Ой, всё, я сдаюсь Аж вьетнамские флешбеки пошли с первого курса, где многие преподы имели милую манеру подавать материал в аналогичном "сокращённом" виде без разжёвывания. Надеюсь, каждый из них получит в аду личный котелок с антипригарным покрытием, хе-хе Но если не трудно, то не мог бы ты прояснить момент хотя бы с логикой сравнения остатка от деления? Мне правда очень интересно
  11. Разве библиотека shell на ComputerCraft не глобальна? И существует ли там вообще require? Не os.loadAPI?
  12. Это значит, что она где-то создана в проге. Ты в этой жизни определен в свидетельстве о рождении под какую-то конкретную дату с сопутствующей инфой о месте регистрации. С функциями (командами) та же история: они имеют имя, тело (код, который они выполняют) и место определения в проге (номер строки) Да, но это консольная команда, а не команда для обращения к редстоун-модулю из кода. Чтобы заставить свою прогу работать, ты можешь глянуть на исходный код redpulse.lua и модифицировать его под свои нужды: while true do F = redstone.getInput("front") if F then -- Либо используешь собственный код redstone.setOutput("back", true) sleep(3) redstone.setOutput("back", false) sleep(3) -- Либо запускаешь оригинальный redpulse, без разницы shell.run("redpulse back 1 6" ) end sleep(1) end
  13. ECS

    Не работает сортировка

    Хе-хе, я ждал этого вопроса. Как говорится, пути компиляторов неисповедимы: к примеру, если каким-либо образом обрабатывать элементы таблицы, создавая иллюзию реальной деятельности в теле цикла, то ipairs, разумеется, проигрывает, т.к. это функция-итератор, которая чисто технически не может быть быстрее простого цикла с числовым лимитом: Bench() :Add("for i = 1, #tbl do", function() for i = 1, #tbl do local var = math.floor(#tbl[i]) end end) :Add("for i, v in ipairs(tbl) do", function() for i, v in ipairs(tbl) do local var = math.floor(#v) end end) :Start(100000000) Если же получить элемент таблицы и ничего с ним не делать, то компилятор оптимизирует тело второго цикла, банально удалив "лишнее" присвоение. При этом индексация в первом случае останется нетронутой, и создастся иллюзия ускорения: Bench() :Add("for i = 1, #tbl do", function() for i = 1, #tbl do local var = tbl[i] end end) :Add("for i, v in ipairs(tbl) do", function() for i, v in ipairs(tbl) do local var = v end end) :Start(100000000) А вот в этом случае ipairs опять в пролёте даже несмотря на дополнительную индексацию по таблице в теле первого цикла, т.к. накладные расходы на вызов функции-итератора превышают расходы на индексацию таблиц: Bench() :Add("for i = 1, #tbl do", function() for i = 1, #tbl do local var = #tbl[i] + math.floor(i) end end) :Add("for i, v in ipairs(tbl) do", function() for i, v in ipairs(tbl) do local var = #v + math.floor(i) end end) :Start(100000000)
  14. ECS

    Не работает сортировка

    Не-а. Специально даже скомпилил LuaJIT из интереса, а для честности оба тела цикла сделал максимально простыми, дабы тестить исключительно итерационную составляющую: Bench() :Add("for i = 1, #tbl do", function() for i = 1, #tbl do local var = 1 end end) :Add("for i, v in ipairs(tbl) do", function() for i, v in ipairs(tbl) do local var = 1 end end) :Start(10000000)
  15. ECS

    Не работает сортировка

    Согласен, я и сам предпочитаю использовать ipairs в простых скриптах, где производительность не играет роли. Однако насчёт локальной переменной ты тут лишка хватил, т.к. любой итератор по типу pairs/ipairs является не более чем функцией-обёрткой, хранящей этот самый счётчик в виде скрытой локальной переменной. Те же яйца, только в профиль: function myIPairs(t) local index, count = 0, #t return function() index = index + 1 if index <= count then return t[index] end end end Я советовал использовать человеку конструкцию for i = 1, #t в первую очередь из-за потенциальной ошибки "хаотичного" порядка вывода игроков, т.к. у меня зачастую именно pairs был виной подобному поведению. А поскольку исходный код софта выложен не был, предположение могло оказаться не лишним. Это потом уже пошла дискуссия на тему "как быстрее"
  16. ECS

    Не работает сортировка

    Во-первых, твой тест заведомо некорректен, т.к. в первом случае при каждой итерации ты индексируешь таблицу (причём индексация - это довольно жирная операция), а во втором тело цикла попросту пустое. Уверен, что JIT-компилятор скипает цикл во втором случае, пытаясь оптимизировать код: Во-вторых, тема твоего поста и моя рекомендация по ipairs относится к опенкомпам, где по дефолту не поддерживается JIT-компиляция. Зачем прилагать бенчмарк на GMod/LuaJIT вместо бенчмарка на опенкомпах - мне не ясно В-третьих, у тебя используется GMod'овский таймер вместо нативного os.clock, который, напомню, и следует использовать для бенчмарка алгоритмов согласно Lua wiki Поэтому если адаптировать твой код под чистый луа, то результат будет диаметрально противоположным: local function Benchmark(uid, func, count, onfinish) local time = os.clock() for i = 1, count do func() end print(uid, os.clock() - time) if onfinish then onfinish() end end ....................... Bench() :Add("for i = 1, #tbl do", function() for i = 1, #tbl do local var = tbl[i] end end) :Add("for i, v in ipairs(tbl) do", function() for i, v in ipairs(tbl) do local var = v end end) :Start(10000000) -- 10 000 000 Ой, что же это? Медленнее в 2.7 раза? Ой-ой-ой
  17. ECS

    Не работает сортировка

    Начнём с того, что изначальный метод сортировки невалиден для table.sort, т.к. не учитывал все возможные варианты напрямую. Да, нативный sort в этом плане слегка туповат: Также рискну предположить, что вывод игроков на экран был хаотичным из-за использования for k, v in pairs вместо for i = 1, #array (который, к слову, еще и быстрее). Поэтому вот: local members = { { name = "Vasya", online = false, playtime = 10, offline_time = 2 }, { name = "Petya", online = true, playtime = 14, offline_time = 2 }, { name = "Sanya", online = true, playtime = 15, offline_time = 2 }, { name = "Igor", online = false, playtime = 1, offline_time = 3 }, { name = "Dima", online = false, playtime = 1, offline_time = 8 }, } table.sort(members, function(ply1, ply2) if ply1.online and ply2.online then return ply1.playtime > ply2.playtime elseif ply1.online and not ply2.online then return true elseif not ply1.online and ply2.online then return false else return ply1.offline_time < ply2.offline_time end end) for i = 1, #members do print(members[i].name) end Результат:
  18. ECS

    No such component

    Ошибка "no such component" всегда возникает при попытке доступа к proxy компонента, записанному в переменную, если по какой-то причине сам компонент был физически отсоединён. А вот почему он отсоединился - фиг знает: либо сервак пролагал, либо с выгружающимися чанками проблема, либо возникает коллизия UUID'шников компонента (что маловероятно), либо вообще админ/сожитель своими кривыми ручонками пошарился. Исправить ситуацию можно путём периодического обновления proxy на актуальный через computer.uptime В любом случае ставлю последний счетверённый МОХ, что 108 строка ошибки просто "сдвинулась" в трейсе на единицу, и isAvailable тут ни при чём. Пруф:
  19. Метод упоминается только на этом форуме в виде чейндж-лога, в документации на гите он отсутствует, и в процессе эволюционирования либы был выпилен по причине фиговой производительности. Если честно, то оставить его проблем не составило бы, однако либа менялась, принцип рендеринга тоже, принцип хранения кадров вообще расслоился на 6 таблиц вместо изначальных 2х, и долгосрочная поддержка неиспользуемой фичи мне показалась накладной. Да и браузер твой загнётся на фиг при отрисовке, т.к. formattedText имел тонну лишних условий и обрезок строк в каждой итерации отрисовки в буфер Что там просчитывать-то, один раз в цикле заюзать unicode.len()? И зачем хранить постоянно координаты смещений каждой цветной строки? Не эффективней ли будет организовать структуру таблицы в виде изначальной точки первого символа и перечислений вида "цвет, строка, цвет, строка."? Чет тип такого: local lines = { { 2, 5, 0xFFFFFF, "Hello world!", 0xFF0000, " It's a red symbols", ...} } local line, x, y, str for l = 1, #lines do line = lines[l] x, y = line[0], line[1] for i = 3, #line, 2 do str = line[i + 1] buffer.drawText(x, y, line[i], str) x = x + unicode.len(str) end end
  20. Для меня прям загадка, какая ж у тебя версия либы используется: метод был оч давно добавлен в старую, но удален при переходе на майноську ввиду низкой производительности и отсутствия практического применения. Обычно я юзаю несколько drawText со смещением по X и разными цветами друг за дружкой. А для каких целей метод пригодился бы, если не секрет?
  21. Мяу, ну явно ж какая-то кастомная отрисовка пикч идет у тебя в RenderEngine. Без сырцов фиг знает, что там происходит, и как это пофиксить. Вполне вероятно, кстати, что на скрине старая либа Image используется, где была иная RAM-структура картинок (с вложенными таблицами), а либа буферизации - новая. Я потому и прекратил поддержку всего этого балагана, т.к. по кускам собирать код никаких нервов не хватит Если критично - можешь просто выдрать обновленный и исправленный метод drawSemiPixelRectangle к себе в старую либу
  22. Надо же, до сих пор интересные баги всплывают! Ладно, фигня вопрос, сейчас пофиксим, тут проблема в смещении пикселей за пределами drawLimit ввиду одномерной структуры буфера экрана. Только учти, что эта либа - неподдерживаемое legacy, и основная версия находится в виде Screen API в майноське. Полупиксельный метод я обновлю, но никаких гарантий по работоспособности остальных методов нет, все дела
  23. Обновил доку по Image API, спасибо за наводку. Есть подозрение, что она уже года полтора как валялась пустующей
  24. В случае невозможности открытия картинки image.load() выдаст false и причину, по которой это происходит. Возможно, файл был повреждён или же банально не хватает оперативки. Ну а GUI.image - это всего лишь обёртка над заранее загруженным изображением, и если пихать в неё boolean вместо самой картинки, то либа сдохнет. Почему же нет проверки на тип данных, чтобы предотвратить такие ситуации? Потому что тонны assert'ов и вызовов type() с последующим сравнением убивают и без того слишком малую производительность опенкомпов. Либа спроектирована по принципу перекладывания ответственности на программиста: такова цена спасения. Поэтому юзай следующий код и проверяй валидность пикч вручную: local result, reason = image.load("test.pic") if result then local image = GUI.image(1, 1, result) ... else GUI.alert("Хопа! Пiймав на сломанную пикчу: " .. reason) end Я было хотел ткнуть носом в документацию, мол, "читай сначала, блеан", но только сейчас заметил, что она сдохла как раз в разделе Image API. Пардоньте, щас исправим))0
×
×
  • Создать...