• А как реализуют всякие разархировщики файлов игр для модификаций?

    @Mercury13
    Программист на «си с крестами» и не только
    Сам я бросил ковырять игры давным-давно, и мои знания устарели. Но вот в старых играх, где упаковки ещё не было, я успешно распознавал кое-какие форматы. Но в целом задача состоит из двух: опознание формата архива и опознание формата файла в архиве.

    Архив, как правило, устроен просто (хотя разработчики могут зашифровать его, как в «Мафии»). Разжатие чаще всего делается каким-нибудь из стандартных алгоритмов типа Deflate или LZMA. В принципе, можно и игру дизассемблировать, если алгоритм необычный, но чаще всего нет нужды. Кстати, разжатие из-за того, что оно критично к скорости, не покрывают всякими там Denuvo.

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

    Для утилит используют любой доступный язык высокого уровня, чаще всего Си++.
    Ответ написан
    Комментировать
  • Как пишутся библиотеки для C++ и других ЯП?

    @Mercury13
    Программист на «си с крестами» и не только
    В 99,9% случаев — на языках высокого уровня. Как слой более низкого уровня используются три вещи.
    1. Стандартная библиотека языка.
    2. Внутреннее API ОС (WinAPI/POSIX/DOS).
    3. Чужие низкоуровневые библиотеки.

    Есть такое понятие «полнота по Тьюрингу» — грубо говоря, это значит, что язык способен решать те же задачи, что и машина Тьюринга (простое гипотетическое программируемое устройство). Все языки программирования полны по Тьюрингу, то есть ими можно закодировать любой алгоритм, зачем ассемблер?
    Ассемблер используется ограниченно во внутренних циклах, где важна скорость.

    Здесь под «низким уровнем» понимается «мало автоматизации», «очень тонкая прослойка между API операционной системы и нашим новым интерфейсом», «минимум управления памятью» — то есть функция, например, принимает не std::string, а указатель на нуль-терминированную строку const char*. И для написания библиотек любят языки, способные работать на низком уровне — в первую очередь Си, Си++ и Паскаль. Если нет ограничения по скорости, ассемблер не обязателен.
    Ответ написан
    1 комментарий
  • Как открыть порт на роутере? Комплексное решение?

    @Mercury13
    Программист на «си с крестами» и не только
    1. https://portforward.com/tp-link/tl-wr740n/
    www.pcwintech.com/port-forwarding-tp-link-tl-wr740...
    forum.tp-linkru.ru/viewtopic.php?t=9
    Но не забывайте, что это требует статического IP-адреса сервера, и лучше всего это сделать, прописав статическую зависимость MAC-IP. По третьей сцылке это есть.
    2. Гуглите UPnP. Посмотрите, допустим, вот. Использование UPnP C++
    3. Сам даже не знаю. Как-то само из кусочков понимание собралось. Правда, я в своё время налаживал локальные «сети» по COM- и LPT-кабелю. А потом по-чёрному резался в разные игры по интернету. Разумеется, тонкостей настройки больших сетей мне это не дало, но как ходят пакеты, примерно понимаю.
    Ответ написан
    2 комментария
  • Какие есть проблемы при работе генетических алгоритмов?

    @Mercury13
    Программист на «си с крестами» и не только
    3 = Сходимость к произвольной точке.
    4. Плохая сходимость.
    5. Не получается придумать качественную процедуру кроссинговера (её задача — поддерживать разнообразие популяции).
    Ответ написан
    Комментировать
  • Что означает "+" после регистра?

    @Mercury13
    Программист на «си с крестами» и не только
    Перед нами синтаксис ассемблера Intel.
    qword ptr [] — адрес восьмибайтовой переменной в памяти. Если конкретный — прямая адресация, если внутри какой-то регистр — косвенный.
    + — простая операция сложения.

    Перед нами косвенная адресация со смещением. То есть, берём содержимое регистра eax, прибавляем 80h, обращаемся по этому адресу и то, что получилось, загоняем в стек сопроцессора как double.

    ЗЫ. Подобный полный показ команд с ведущими нулями и без указателя 16-й системы (80h) обычно используется в дизассемблерных листингах.
    Ответ написан
    3 комментария
  • Нужно ли солить хеш длинного случайного сессионного ключа в БД?

    @Mercury13
    Программист на «си с крестами» и не только
    Для чего вообще солят хэши? Против сливов БД: если хэши ушли, по ним сложно восстановить пароли.
    • Если при подозрении на слив мы можем перегенерировать ключи или объявить их просроченными;
    • Если ключи держатся где угодно, только не в БД;
    • Если ключи настолько длинны и случайны, что сложновато будет обратить алгоритм объединёнными хакерскими силами
    — то зачем?

    Впрочем, не забывайте, что хэшируя, вы автоматически снижаете криптостойкость вашего алгоритма до длины хэша. А может, проще изначально делать ключи такой длины?
    Ответ написан
    Комментировать
  • Как процессор работает с памятью?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Для косвенной адресации. Мы не просто обращаемся к 325-й ячейке, а проводим вычисление, получаем 325 и обращаемся к ячейке с этим номером. Получили бы 456 — обратились бы к 456-й.
    Это даёт кучу интересных структур данных, и самая простая из них — массив.

    Многоуровневый указатель — это уже дело более высокого уровня. Пока указателем я называл просто адрес в памяти. Но, извините, в памяти хранятся однобайтовые целые, двухбайтовые целые, дробные, массивы, строчки, другие указатели — в общем, на более высоком уровне появляется понятие «тип данных». И указатели бывают на целое, на дробное — и на указатель!

    2. Разница между каким-то адресом и началом структуры данных. Например, у нас есть такая структура данных (для простоты без выравнивания).
    a : word
    b : dword
    c : byte

    Тогда поле c находится по смещению 2+4 = 6, и если голова структуры по адресу 124, то поле c будет по адресу 124+6=130.

    Также в стандартном режиме 8086 — 16-битный процессор с 1 мегабайтом адресуемой памяти — была хитрая система адресации под названием «сегмент:смещение», и адрес вычислялся по формуле сегмент·16 + смещение. При этом было принято считать, что сегмент незыблем, а по структуре данных (которая при этом не могла превышать 64K) мы двигались, меняя смещение.

    3. Т.н. «переключение контекста» — ядро ОС просто сохраняет регистры в памяти. Очень долгая задача, кстати.
    Ответ написан
    Комментировать
  • Как правильно оценить временную сложность алгоритма?

    @Mercury13
    Программист на «си с крестами» и не только
    В общем случае да. Но иногда подобные оценки можно упростить. И упрощения можно делать по двум статьям:
    1. Более точные оценки. В данном случае не могу придумать.
    2. Более простые оценки: ведь оценка — это символ Ландау O(f(·)), который с точностью до константы. Если, например, K<N, а L<M, то сложность будет просто N·M.
    Ответ написан
    Комментировать
  • При завершении работы программы падает исключение, что делать?

    @Mercury13
    Программист на «си с крестами» и не только
    Это испорченная память, где-то ошибка в управлении памятью (например, запись за границами массива).
    UPD. Ваша ошибка: в составе std::string есть внутренние неконтролируемые поля, и его нельзя побайтово сохранять в файл. Такими неконтролируемыми полями могут быть указатели, кэши-ускорители и многое другое. Вообще std::string состоит из указателя или двух, и отсюда следуют две вещи. 1) При сохранении в файл не попадут строковые данные, попадёт только указатель. К тому же в Windows нет хорошего 16-ричного просмотрщика, а без него при работе с файлами как без рук (по крайней мере начинающему, я давно обхожусь). 2) Как только вы этот указатель загрузите, std::string портится, и на деструкторе может случиться что угодно.

    Вам надо самим придумать формат файла и реализовать загрузку/сохранение, используя length(), data() и front().

    Важное правило: ткни в любой байт дампа вашего файла — вы должны сказать, что он значит. Из-за сложности формата это может быть сложно. Байт может быть неиспользуемым или оставленным для совместимости, но какое-то значение должно быть. Если формат многоуровневый, надо сказать назначение на всех уровнях: например, «это значение атрибута XML» на уровне XML и «это имя студента» на прикладном уровне.

    Исключение: если есть объект-«чёрный ящик», который написан не нами и сериализуется гарантированно корректно, достаточно сказать: «это часть чёрного ящика». (Сериализуется — это переводится в цепочку байтов, например, файл или сетевой поток.)

    Что ещё пока вижу (но это не причина ошибки).
    1.
    unsigned short int *exam_t = new unsigned short int[5];
    Нет нужды new, невелик массив. Хватает локального массива на стеке. Аналогично остальные два new.
    2. Нет нужды давать clear/close. Это фишка Си++, автоматически сработает деструктор.
    3. Не называйте переменную flag, называйте wasFound (или что она реально значит).
    4. sizeof(&student_r) только чудом совпадает с sizeof(student_r).
    5. Не надо писать flag == false, надо !flag.
    6. Функция del_reversive делает излишнюю работу и переставляет студентов, к тому же есть стандартный алгоритм remove_if.
    7. while (!flag) в del_rev бессмысленно.
    8. Вы же работаете со string’ами — зачем вводить информацию в буфер ограниченной длины?
    9. Программа не модульная, нет нужды в хедере.
    Ответ написан
    Комментировать
  • Существуют ли правила подключения include-файлов в С++?

    @Mercury13
    Программист на «си с крестами» и не только
    Незыблемых правил два.
    1. В CPP первым — свой хедер. Это даёт уверенность, что в хедере нет недостающих включений.
    2. Избегать циклической зависимости по интерфейсам. Делить программу на слои и не включать ничего из верхних слоёв.

    Если уж второе не получилось — есть три решения, каждое из которых решает свою задачу.
    1. Forward declaration, полумера против сильной связанности классов.
    // Хедер 1
    class Master;
    
    class Slave {
      Master* master;
    }
    
    // Хедер 2
    class Master {
      Slave slave;
    }


    2. Разорвать порочный круг интерфейсом.
    // Хедер 1
    class Master {  // interface
    public:
      virtual void enumSlaves(const EnumSlavesCallback& v) = 0;
      virtual ~Master() = default; 
    }
    
    class Slave {
      Master* master;
    }
    
    // Хедер 2
    class MyMaster :  public Master {
    public:
      Slave slave;
      void enumSlaves(const EnumSlavesCallback& v) override {}
    }


    3. Вынести общие типы/функции в отдельный хедер под названием someDefines.h или someUtils.h.
    Ответ написан
    Комментировать
  • Можно ли монетизировать ролики переозвучки?

    @Mercury13
    Программист на «си с крестами» и не только
    Нашёл интересную статью, и судя до ней, есть шансы, что видео примут за добросовестное использование.
    fairusetube.org/guide-to-youtube-removals/3-decidi...
    Ответ написан
    Комментировать
  • Как можно решить эту задачу логически иначе?

    @Mercury13
    Программист на «си с крестами» и не только
    В лоб.
    Если a > b, обменять a и b.
    Если a > c, обменять a и c.
    Если b > c, обменять b и c.
    Меньшим количеством обменов это сделать невозможно: два обмена дают до 4 вариантов расстановки, а 3!=6.
    Ответ написан
    Комментировать
  • Зачем нужны отверстия с эластичными лепестками в корпусе системного блока?

    @Mercury13
    Программист на «си с крестами» и не только
    Тянуть трубы системы водяного охлаждения.
    Ответ написан
    Комментировать
  • Как правильно организовать код большого проекта на C++(и не только)?

    @Mercury13
    Программист на «си с крестами» и не только
    Имена классов с большой буквы в CamelCase, например class EventHandler;.

    Принято в Java, Qt.

    Названия объектов аналогично, но первая буква маленькая, например Image backgroundImage;.

    Принято в Java, Qt.

    Названия примитивных типов(int, char, double, etc) маленькими через нижнее подчёркивание, например double percent_of_fails;

    Думайте как хотите, но, по-моему, нет нужды.

    Названия методов с мальнькой в camelCase и отражают действие функции, например void addModule(std::shared_ptr module);

    Принято в Java, Qt.

    Структура файлов:

    При таком количестве файлов (и даже впятеро большем) — норма.

    Первым идёт инклуд C++ хедеров, затем сторонние библиотеки типа буста, затем *.i файл из данной директории и после всё остальное.

    Свой хедер → стандартные библиотеки Си/Си++ → сторонние библиотеки, причём чем больше мы от них архитектурно зависим, тем они раньше → внутренние файлы (опять-таки, движок раньше утилит и наборов данных).

    Первым свой хедер — это архиважно. Как правило, модули идут парой «хедер + единица компиляции», и мы сразу же убеждаемся, что в хедере есть все нужные #include.

    1 forward declarations(чтоб не замусоривать ими остальные файлы)

    Forward declarations конкретно чего?

    2 инклуды всех *.h файлов из данной директории.

    Пункт спорный даже не из-за перекомпиляции, а из-за 1) циклической зависимости между модулями; 2) если сделать это в хедере — может привести к некомпилирующемуся проекту.

    Сущности в каждой директории имеют своё одноимённое пространство имён,

    Пространств имён должно быть намного меньше, чем файлов, плюс они должны быть предельно короткими. Избегать using namespace.

    Кроме того…
    1) Рекомендую в каталоги поиска хедеров поставить основной каталог проекта. В #include ни в конем случае не должно быть «каталог вверх» (..).
    2) Возможно, чужие библиотеки стоит вынести из каталога проекта. Их каталоги также стоят в каталогах поиска хедеров.
    3) Категорически запрещены повторы файлов в разных каталогах.
    Ответ написан
    2 комментария
  • WinAPI: Нарушение прав доступа при записи. Как исправить?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Ошибка в вызове ReadFile. Причём я говорил про эту ошибку.
    DWORD nRead;
     isSucceed = ReadFile(myfile, buffer, 10, &nRead, NULL);


    А также.
    2. Файл открывать только для чтения.
    3. Проверить myFile на корректность.
    4. Читаем 10 байтов, пишем 100?
    Ответ написан
    Комментировать
  • Как вывести результат работы функций WinAPI?

    @Mercury13
    Программист на «си с крестами» и не только
    Ваши ошибки.

    1. Это разные дескрипторы.
    FindFirstFile даёт дескриптор поиска файлов.
    А ReadFile требует дескриптор файла, который можно получить через CreateFile.

    2. Второй параметр FindFirstFile не может быть NULL. Это указатель на WIN32_FILE_DATA, в которую функция и будет кидать информацию о найденных файлах.

    3. Если вы не ищете по маске и точно хотите открыть файл, на что вам FindFirstFile? Орудуйте сразу CreateFile.

    4. Вы подключили пару излишних хедеров.

    5. Не советую вместо нулевого указателя NULL писать 0.

    6. В ReadFile два последних параметра не могут одновременно быть NULL: первый — для синхронного чтения, второй — для асинхронного.

    В общем, «курите маны». Благо, у M$ они хорошие.
    Ответ написан
    9 комментариев
  • Как правильно настроить характеристики врагов и оружия (урон, здоровье и тп), чтобы соблюдался баланс?

    @Mercury13
    Программист на «си с крестами» и не только
    Да, это называется игровой баланс. Дело сложное и мутное, единого подхода нет.

    Рубиться компьютер на компьютер — помогает в маргинальных случаях и свидетельствует о бедном геймплее. Сложных героев наподобие Ио или Оракула из Доты попробуй отработай. (Хотя все последние герои сложные, начиналось всё ≈2007 с героев поддержки, но потом всяких наделали: и танков, и дамагеров.)

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

    Вот у нас есть гипотетическая Лунная Наездница, которая не имеет длительных дисейблов (зато догонит почти любого), каждые 6 секунд даёт магию на 250hp и раз в секунду даёт удар на 50hp. Вот и получается: за кулдаун нюка она сносит 300 hp. Другими словами, больше урона она наносит руками, чем магией. Сколько должен наносить гипотетический Гном-снайпер, который вообще не имеет магии и бьёт только своим ружьём (с такой же скоростью)? Получается, что 90hp. Многовато, но можно дать Снайперу фору другими методами. Поскольку первые уровни Доты — это «перестрелка на Угре» из-за спин крипов, можно дать ему большую дальность, и он зачморит Наездницу. Можно дать подствольник, который будет эффективен против крипов с первых же уровней.

    Особые сложности начинаются, когда в игру входят полубоевые персонажи (дисейблеры, киллеры и прочие). Один держит, второй палит — сколько секунд держать? И, считаю, только под Valve решились основные косяки с Дотой.

    Поскольку игра длится в пространстве и времени, надо понимать, как та или иная местность, тот или иной этап игры помогает тому или иному герою. Сможет ли игрок выстоять «не в своей тарелке» и пережить чужой «золотой век»? Какие нужно для этого принять решения? Это больше творчество, чем наука.

    Но прежде, чем собирать баланс, надо… 1) Собрать приблизительное видение игры; 2) Сделать прототип; 3) Собрать общую картину баланса — и только тогда можно раздавать характеристики разным персонажам.
    Ответ написан
    Комментировать
  • Какую версию Indy 10 использовать для Delphi 7 под Windows 10?

    @Mercury13
    Программист на «си с крестами» и не только
    Многие библиотеки OpenSSL требуют какие-то свои DLL (например, MSVC). Если программа внутренняя, это не так важно, а вот если её распространять… Особенно когда программа написана на чём-то другом, кроме MSVC: например, MinGW или Delphi.
    Я накопал вот такие сборки — они выполнены устаревшей версией MSVC и не требуют ничего особенного.
    https://indy.fulgan.com/SSL/
    (Сам я использую MinGW, и поскольку OpenSSL вызывается через cURL, который тоже не мой, без бутылки не поймёшь, кто виноват и что делать.)
    Ответ написан
    Комментировать
  • Как посчитать вероятность выпадения K раз числа на отрезке N?

    @Mercury13
    Программист на «си с крестами» и не только
    C104·(5−1)10−4
    Расставляем единички (C104) способов, затем ставим всё остальное ((5−1)10−4).

    Чтобы подсчитать вероятность, надо ещё разделить на 510
    Ответ написан
    Комментировать
  • Какова адресация элементов структуры в си?

    @Mercury13
    Программист на «си с крестами» и не только
    Да, будет хранить в том порядке, в котором записал. Гуглите понятие POD = Plain old data.
    en.cppreference.com/w/c/language/struct
    Ответ написан
    Комментировать