Igor
Но обычно это происходило только под linux
Igor
Почему - мне неведомо, но переодически функция send возвращала размер пакета меньше, чем переданная строка
Igor
Возможно это связано с настройкой таймаута в ноль, чтобы сокет был неблокирующим, но на той же винде это проблем не вызывало, а на этих двух ОСях сокеты работают, ну.... почти одинаково. С натяжечкой одинаково
Highly Likely
TCP в самом протоколе не может не доставить пакет, емнип :-)
Igor
Я сам не знаю, как это происходило, но size на выходе client:send() был меньше входной строки
Igor
То есть пакет мой доходил, но кусками, а обрабатывать эту отправку кусков приходилось вручную, вот примерно таким же методом, который показал @djapananda
🐅🤦‍♂️
Да, это именно про случай если придет кусками.
Highly Likely
А, ну это нормально :)
Highly Likely
Емнип TCP последовательность не гарантирует
Highly Likely
Это какой-нибудь MPLS делает
Igor
Я раньше думал, что TCP на более низком уровне сам проверяет целостность отправленного пакета
Igor
То есть гарантированно отправляет все данные, пока это возможно
Highly Likely
Igor
Я не говорю, что там неправильная последовательность кусков, в том то и дело, что он отправляет только первые несколько байт от пакета
Igor
А остальные приходится доотправлять самому конструкциями с циклами и обрезкой отправляемой строки, чтобы продолжить отправку с того места, где она прервалась
Highly Likely
А, тогда вероятно это какой-то неведомый баг send’а
Highly Likely
Может @Snusmumriken подскажет лучше
Snusmumriken
Да, у меня был подобный баг с отправкой как раз под вендой, лечилось выставлением минимального таймаута (0.001). Но в целом, там где-то должна быть функция типа "сколько байт от последнего сообщения передано".
Alxius
https://www.youtube.com/watch?v=JJAe2b-kTgs&feature=youtu.be вроде неплохо вышло и вроде всё рассказал, на Голую ОС конечно заново ставить ради видео не стал но кажется ничго не упустил
Highly Likely
Я чот подвисал на словах «нэв», «вине» вместо «нью» и «вайн» :D
Alxius
я в детсве учил английский с помощью Zx-spectrum и польских хакеров взламывавших игры)
Alxius
))))
Alxius
есть отдельное видео посвящённое этим словам) но оно не претендует на общественно полезные
Snusmumriken
Привет @gavr123456789.
gavr
Привет @gavr123456789.
Сап, все еще изучаю, но идеи мне оч нрав, чем то похоже на смолтолк, минимальный и простой синтаксис с одной концепцией во главе, только если в смолтолке это были все объект, то тут все таблица, почти
Snusmumriken
Ну из таблицы можно слепить хоть объект хоть что, так что суть почти то же, но базовые типы всё ещё есть (хотя со строками можно обращаться как с "объектами"). Если будут непонятки с метатаблицами — читани "краткое введение в метатаблицы" на хабре
Snusmumriken
Так-то ничего сложного, объект как таблица с поиском недостающих ключей (методов/общих свойств) в таблице-классе. А если юзать таблицу-класс как объект, можно получить синглтон даже без метатаблиц.
Snusmumriken
Upvalue в замыканиях, но в целом — соглашение между джентльменами.
Snusmumriken
Называем особые методы/свойства через _private_method, и в них никто не лазает, потому что есть шанс сломать : ) Это прост быстрее всего. Upvalue — отжирают лишнее место и требуют генерации функций для работы с ними для каждого объекта в отдельности, вместо того чтобы дёргать классовые. Сделать "общие" приватные поля можно в локальной табличке в файле с классом, это настолько же быстро как и дёрганье методов класса, но оно общее для всех объектов.
gavr
хех, ясн
Snusmumriken
Ничоси у тебя запросы : ) А что ты хочешь?
Snusmumriken
lua_getglobal(L, "require"); lua_pushstring(L, "cjson"); // например, cjson lua_call(L, 1, 1); int ref = lua_ref(L, -1); Вот у тебя теперь ссылка на табличку-модуль. Когда нужно — вставляешь её в стек, извлекаешь нужную функцию и вызываешь. Запихивание обратно в стек через lua_rawgeti(L, LUA_REGISTRYINDEX, ref); В сишке нет такого понятия как "локально", мы можем разве что не модифицируя глобалспейс луа-стейта вытащить ссылку.
Snusmumriken
Таки зачем нужно?
Snusmumriken
Жуть какая : )
Snusmumriken
Не эффективнее ли предоставить пользователю выбор json-библиотеки, и просто принимать табличку? Прироста в скорости парсинга json'а ты не заметишь, зато вводишь явную и очень жёсткую зависимость.
Snusmumriken
Тем не менее, сишные модули которые зависят от луёвых — это не очень хорошо, да и структура Lua => C ломается :<
Snusmumriken
Ну там, я в своей стимовой либе делал вызов луёвых функций, типа: lua_rawgeti(L, LUA_REGISTRYINDEX, callback_table); lua_getfield(L, -1, "userfunc"); lua_call(L, 0, 0); Но там сама библиотека инициализирует и выдаёт юзеру в пользование табличку callback_table, и запоминает ссылку на неё. Пользователь заносит в неё функции, и дёргает сишную "вызвать колбеки", которая дёргает луёвые. Это конечно тоже не очень хорошо, и по хорошему надо бы выгружать в луа список колбеков, которые были вызваны с предыдущего дёрганья, но у меня не было желания делать сто тысяч миллиардов типов колбеков, там уже особенности самой steamworks. То есть, структура как бы не очень приятная, но хоть нет зависимостей от внешних модулей.
Snusmumriken
Ещё один лайфхак: на луёвой стороне гораздо проще написать код, проверяющий ошибки. На сишке это будет миллиард бессмысленных и беспощадных действий перелопачивания стека, в котором без поллитры потом не разберёшься. Поэтому используй луёвые либы с луями, для своего же блага : )
Snusmumriken
Типа такой: local steam = require'luasteam' -- таблица steam.callback запомнена внутри сишной либы function steam.callback.onFriendMessage(friend, msg) print("Got " .. msg .. " from " .. friend:getName()) end while true do -- Эта штука вызовет функцию (если есть) -- когда наступит событие steam.eventPump() end Если ты пробовал ловку, то схема такая же, только без луёвого фронтенда (там луа сначала получает события, а потом дёргает луёвые же функции если есть).
Snusmumriken
Ну да, после правки — похоже на то.
Snusmumriken
Кстати, через int ref = lua_ref(L, -1); можно запоминать ссылки на функции, например. То есть, у тебя в сишном модуле функция "setJsonDecoder", которая принимает из луа функцию, запоминает, а потом вызывает при нужде. Но тут всё равно проблемы обработки тех же ошибок типа "невалидный json". То есть, тут могут быть ссылки на любые ссылочные типы (коих примерно четыре).
Snusmumriken
Делай функцию колбека такой, чтобы могла выбирать. Например, волшебные переключалки: local main = {} function main.onFriendMessage(...) end local ingame = {} function main.onFriendMessage(...) end local current = main function steam.callback.onFriendMessage(...) if current.onFriendMessage then current.onFriendMessage(...) current = ingame end end Если хочется одновременного вызова — можно завести табличку-список, какие функции надо вызвать.
Snusmumriken
Ты — юзер, имеешь право делать как хочется : ) Разработчик библиотеки делает только основной функционал, все нагромождения на совести юзера.
Snusmumriken
Это будет как в жаваскрипте : ) Вариант конечно вариантный, но плохо заточено под состояния, а в играх в основном они.
Snusmumriken
То есть, при переключении состояния, придётся сначала отзывать все старые события (храня их ID), а потом пихать новые, когда можно было бы просто переключить ссылку на табличку. Плюс хранение списков функций на сишной старане — такое себе дело. Когда мне в какой-то момент пришлось делать что-то такое: friend:getAvatar("large", function(...) end) (потому что вызов асинхронный, а хотелось влепить фичу прям колбековых колбеков), я сделал ещё одну табличку в луёвом регистре, и заполнял её луёвыми функциями (по ключам friend_id), а потом вызывал при случае. На сишке пришлось бы мутить хеши или динамические массивы, добавлять-удалять и делать ещё много неприятных штук. У луа уже есть хеш-массивы, и их можно использовать в т.ч. с сишной стороны. Пусть луёвые данные хранятся на луёвой стороне, в общем.
Snusmumriken
addEventHandler("onSome", userFunc1) Куда отправляется userFunc1? Где оно начинает храниться, чтобы вызываться по событию?
Snusmumriken
1. На сишной стороне в виде int func_ref 2. На луёвой стороне в глобальном реестре (недоступно из луа просто так, типа невидимой но существующей таблицы) 3. На луёвой стороне, где-то в доступной из стейта табличке (вроде той steam.callback)
Snusmumriken
Если третий вариант — то в целом возможно. Но есть несколько неприятных штук: 1. Придётся делать схему работы массива с дырками, в противном случае будет непонятен порядок вызовов (хеш не имеет порядка), или айди будет меняться, и пользователь не сможет удалить конкретный колбек. А с сишной стороны это делать неприятно; 2. Получится почти то же что есть, но только со списком, что мог бы сделать сам юзер; 3. Ну типа избыточное нагромождение. Зачем громоздить когда можно не громоздить? Юзеру нужно нагромождение — он себе сделает, функционала достаточно.
Snusmumriken
Есть такой страшный принцип, под названием KISS. Можешь загуглить на досуге. Вольная интерпретация — не стоит делать сложнее чем необходимо.
Snusmumriken
Ну вот тебе практическое.
Snusmumriken
JS давным-давно ушёл от KISS'а, так что в нём может быть что угодно. Ты им пользуешься, и не понимаешь что происходит не просто под капотом, а даже просто фоном, и стимула изучения особо нет. Вот эти вот ЖСовые let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...) автоматически означают, что там помимо, собственно, твоего кода есть цикл событий, система таймеров и ещё куча мишуры, которая работает отдельно от твоего кода. То есть, всякая мишура на которую ты не можешь повлиять, они будут всегда, самое страшное что ты можешь сделать — их отключить (и то не факт). И всё.
Snusmumriken
Я такого предельно стараюсь избежать, делая работу для пользователя прозрачной. Если какое-то действие совершается — это пользователь его совершил, а не "прога сама чот мутит своё". Поэтому и steam.eventPump(). Это действие нужно совершить, иначе никакие колбеки не будут вызываться, даже если прописаны.
Snusmumriken
Ну ды, и с тех пор оно мне не нравится, потому что я оказываюсь на позиции мартышки, которой выдали песочницу и совочек без контроля происходящего : ) С другой стороны, именно в браузерном ЖС это оправдано. Система-то уже есть, и используется ещё для много чего, чому бы не заюзать для этого. А управлять рантаймом вручную — многие жс-кодеры сломаются.
Snusmumriken
Достаточно не писать в браузерном ЖС.
Snusmumriken
Даже луям можно написать сишно-асмовые либы : )
Anonymous
А кому нибудь в истории человечества удалось разобраться в коде луаджита?
Snusmumriken
Нет : )
Anonymous
Кек
Igor
Но тот где-то в других проектах утонул
Snusmumriken
Ну, по частям разве что. Всё таки очень много специфичных асмов. Там весь прекол в том, что здоровенная кодобаза под кучу разных платформ, если что-то править — придётся искать и фиксить сразу везде, иначе кроссплатформа улетит в тартарары.
Igor
Именно поэтому туда и никто не суётся, а если и суются, то форкают и поддерживают только какую-нибудь одну платформу
Snusmumriken
Теперь добавь пять функций, а потом удали три из середины, сохранив индексы.
Snusmumriken
table.remove — сдвинет все элементы после удаляемого назад, поэтому мы просто делаем tbl["onSome"][2] = nil.
Snusmumriken
И итерировать придётся pairs'ом. А теперь сделай то же самое на сишной стороне : )
Snusmumriken
Нет. Как у нас работает ЖСовый let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)? Он возвращает айдишку, индекс этого события. Если мы закроем дырки просто так — у нас изменятся айдишки. И мы не сможем удалить _конкретный_ колбек.
Snusmumriken
Поэтому нам просто необходимы дырки. А при добавлении новых элементов — надо проверять ближайшую дырку и пихать новый колбек в неё. И если на луях это не сложно, то на сишке более стрёмно.
Snusmumriken
Какую функцию с чем?
Snusmumriken
Или ты предлагаешь так: function foo() ... end setTimeout(foo, 20) removeTimeout(foo)?
Snusmumriken
Ты так автоматически запрещаешь использовать одну и ту же функцию несколько раз с разными таймаутами. За этим там и id, чтобы точно идентифицировать, что именно ты удаляешь.
Snusmumriken
И оно выглядит вот так: let id = setTimeout(foo, 20) removeTimeout(id) И вот работа с этим идентификатором есть в жаваскрипте, сам проверь. Плюс ты предлагаешь перебирать список всех таймаутов/колбеков, это O(n).
fgntfg
И итерировать придётся pairs'ом. А теперь сделай то же самое на сишной стороне : )
nextом же. А на си это тоже можно. Там с динамическими структурами и не такое можно. У тебя, по сути - двунаправленный список. Или 2 вектора, в одном у тебя имена объектов, а во втором - адрес.
Snusmumriken
Тебе захотелось вызывать одну функцию несколько раз на один колбек : )
Snusmumriken
А потом удалить одну из них, а потом добавить ещё пять точно таких же.
Snusmumriken
А я откуда знаю, юзеру может и не такое в голову придти : ) Но тут уже появляется неопределённое поведение. А ещё, при добавлении — надо проверять все функции в списке колбеков: нет ли ещё такого колбека, и если есть — удалять старый и добавлять новый в конец (типа, заставляем его вызываться последним). В противном случае, ты такой добавил две одинаковые функции, удалил одну — а удалилась только первая попавшаяся. А почему не последняя? А почему не все сразу? Опять странное поведение.
Snusmumriken
И как оно должно влиять на порядок выполнения?
Snusmumriken
В общем, айдишки в жаваскрипте введены далеко не просто так, это гарантия однозначности.