Задержка

Smeruxa

Известный
Автор темы
1,359
721
Пишу СФ плагин и вопрос, отправляю сообщение в чат но проблема, как сделать задержку между ними? Если использовать функции популярные то игру тупо фризит до тех пор пока все сообщения не отправятся
 
Решение
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100 миллисекунд
но перед этим создай поток что бы не зафризило игру:
Код:
std::thread test([]()
{
//code
};

test.detach();

или же:
Разработчики, только перешедшие с клео\луа на C++ негодуют из-за необходимости использовать разного рода таймеры и лапшу из GetTickCount'ов вместо полюбившихся функций wait. Но особо ярых фанатов клео это не устраивает, отчего они начинают использовать потоки ради функций вроде Sleep для того чтобы не блокировать цикл игры. Однако это не безопасно. Функции ни GTA ни SAMP'а абсолютно не предназначены для использования в разных потоках и их использование может привести к рандомным крашам.
Выход есть!

Example:
#include <string>...

legendabrn

Известный
Проверенный
122
173
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100 миллисекунд
но перед этим создай поток что бы не зафризило игру:
Код:
std::thread test([]()
{
//code
};

test.detach();

или же:
Разработчики, только перешедшие с клео\луа на C++ негодуют из-за необходимости использовать разного рода таймеры и лапшу из GetTickCount'ов вместо полюбившихся функций wait. Но особо ярых фанатов клео это не устраивает, отчего они начинают использовать потоки ради функций вроде Sleep для того чтобы не блокировать цикл игры. Однако это не безопасно. Функции ни GTA ни SAMP'а абсолютно не предназначены для использования в разных потоках и их использование может привести к рандомным крашам.
Выход есть!

Example:
#include <string>
#include <chrono>

#include "Yet-another-hook-library/hook.h"
#include "sampapi/CChat.h"

#include "coro_wait/coro_wait.h"

using namespace sampapi::v037r1;

void foo() {
    using namespace std::chrono_literals;
    CChat *&pChat = RefChat();

    while (!pChat) {
        this_coro::wait(100ms);
    }

    unsigned int counter = 0;
    while (true) {
        pChat->AddMessage(-1, (std::string("Hello ") + std::to_string(counter)).c_str());
        counter++;

        this_coro::wait(1s);
    }
}

void CGame_Process_hk() {
    static coro_wait instance{ foo };

    instance.process();
}

class coro_wait_example {
public:
    coro_wait_example() {
        using CGame_Process_t = void(__cdecl*)();
        CGame_Process_t CGame_Process = reinterpret_cast<CGame_Process_t>(0x53BEE0);

        static hook CGame_Process_hook(CGame_Process, CGame_Process_hk);
    }
} coro_wait_example;

Выполнение функции foo приостанавливается на время, переданное функции this_coro::wait, и продолжается с того же места. Все это работает в одном потоке, благодаря чему можно не переживать за потокобезопасность вызываемых внутри функций.
В бесконечных или очень больших циклах требуется вызывать wait(0), все по канонам клео.
Функция coro_wait::process должна вызываться в потоке игры (перехваченном как в примере, либо в функции mainloop для SF API).

Требуется библиотека Boost.Context!

Исходный код:


хуки
sampapi
 
  • Нравится
Реакции: Smeruxa

Smeruxa

Известный
Автор темы
1,359
721
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100 миллисекунд
но перед этим создай поток что бы не зафризило игру:
Код:
std::thread test([]()
{
//code
};

test.detach();

или же:
буду использовать первый вариант, пасиба, работает
 

Dark_Knight

Me, me and me.
Друг
4,078
2,095
@Smeruxa
первый вариант хуета, а второй заебись. потоки лучше юзать в крайне редких случаях, когда действия в главном цикле игры могут так нихуево грузить систему в момент исполнения кода, если этот код не прям нужный, то можно юзать их. Для всех остальных случаев лучше использовать таймеры.
 
  • Нравится
Реакции: Smeruxa

Ya Zaregalsya

Известный
387
135
@Smeruxa
первый вариант хуета, а второй заебись. потоки лучше юзать в крайне редких случаях, когда действия в главном цикле игры могут так нихуево грузить систему в момент исполнения кода, если этот код не прям нужный, то можно юзать их. Для всех остальных случаев лучше использовать таймеры.
Можно подробнее насчёт таймеров? Я использую функцию CreateThread, с ней вроде нет никаких проблем по части производительности даже когда таких потоков очень много.
 

Dark_Knight

Me, me and me.
Друг
4,078
2,095
Можно подробнее насчёт таймеров? Я использую функцию CreateThread, с ней вроде нет никаких проблем по части производительности даже когда таких потоков очень много.
Потоки зло. Они тебя сожрут, а так без кода ничего и не скажешь.
 

Ya Zaregalsya

Известный
387
135
Потоки зло. Они тебя сожрут, а так без кода ничего и не скажешь.
Для каких задач мы используем потоки: когда надо сделать бесконечный цикл, и когда нужно сделать функцию с задержками, не прерывая выполнение всей программы. Как советуете решать эти задачи?
 

Dark_Knight

Me, me and me.
Друг
4,078
2,095
Для каких задач мы используем потоки: когда надо сделать бесконечный цикл, и когда нужно сделать функцию с задержками, не прерывая выполнение всей программы. Как советуете решать эти задачи?
Код правильно писать. Задержки вообще плохая практика.
 

sc6ut

неизвестный
Модератор
382
1,089
Для каких задач мы используем потоки: когда надо сделать бесконечный цикл, и когда нужно сделать функцию с задержками, не прерывая выполнение всей программы. Как советуете решать эти задачи?
@Dark_Knight, наверное, говорит про написание DLL библиотек, где создание потоков и взаимодействие с памятью приложения может вызвать UB, к примеру из-за одновременного изменения того же участка памяти, так как это будет довольно сложно предотвратить. В создание самостоятельной программы, в использование потоков я не вижу ничего плохого, но надо уметь с ними работать чтобы не происходили возможные проблемы с ними.
UPD: Собственно надо и правильно понимать когда использование потоков востребовано, а когда можно обойтись без него.
 
  • Нравится
Реакции: legendabrn и Ya Zaregalsya

Ya Zaregalsya

Известный
387
135
@Dark_Knight, наверное, говорит про написание DLL библиотек, где создание потоков и взаимодействие с памятью приложения может вызвать UB, к примеру из-за одновременного изменения того же участка памяти, так как это будет довольно сложно предотвратить. В создание самостоятельной программы, в использование потоков я не вижу ничего плохого, но надо уметь с ними работать чтобы не происходили возможные проблемы с ними.
Dark Knight просто немножко чепуху задвигает, потому что это не программист решает, что ему нужна задержка, а в основном так просто стоит задача. Часто сталкиваюсь с UB, например вот артефакты и странные зависания при эмуляции входящих RPC в потоке:


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

kin4stat

mq-team · kin4@naebalovo.team
Всефорумный модератор
2,744
4,806
Либо что-то типа такого
C++:
static bool Process = false;
static unsigned long dwStartTick{ GetTickCount() };
if (Process && GetTickCount() - dwStartTick > 5000) {
    //Код который должен срабатывать через 5 секунд
    Process = false;
}

if (NeedToSendMessage) {
    Process = true;
    dwStartTick = GetTickCount();
    NeedToSendMessage = false
}
Вместо GetTickCount можно использовать std::chrono::steady_clock()

upd: сейчас подумал, и понял что корутины будут использовать такой же принцип работы
 

Ya Zaregalsya

Известный
387
135
Либо что-то типа такого
C++:
static bool Process = false;
static unsigned long dwStartTick{ GetTickCount() };
if (Process && GetTickCount() - dwStartTick > 5000) {
    //Код который должен срабатывать через 5 секунд
    Process = false;
}

if (NeedToSendMessage) {
    Process = true;
    dwStartTick = GetTickCount();
    NeedToSendMessage = false
}
Вместо GetTickCount можно использовать std::chrono::steady_clock()

upd: сейчас подумал, и понял что корутины будут использовать такой же принцип работы
Корутины выглядят непонятно, но многообещающе. Функция, которую можно приостановить — это то, что надо. Надеюсь оно заработает в ГТА и СФ.
 

Dark_Knight

Me, me and me.
Друг
4,078
2,095
потому что это не программист решает, что ему нужна задержка, а в основном так просто стоит задача.
А вот про первое ты как раз вообще не прав. Как программист решает, как решить задачу, а не задача решает, как код программисту решить.
и что же за РПЦ ты там эмулируешь, что ловишь такие артефакты?)
Тебе вон выше дали хорошую либу для таймеров. Ты в ГТА вообще забудь про слово поток. Это крайне плохая практика в этом сегменте.
Вот тебе еще одна
 

Ya Zaregalsya

Известный
387
135
А вот про первое ты как раз вообще не прав. Как программист решает, как решить задачу, а не задача решает, как код программисту решить.
и что же за РПЦ ты там эмулируешь, что ловишь такие артефакты?)
Тебе вон выше дали хорошую либу для таймеров. Ты в ГТА вообще забудь про слово поток. Это крайне плохая практика в этом сегменте.
Вот тебе еще одна
На видео эмуляция различных RPC для установки позиции и направления камеры, их всего пять примерно, когда-то задавал вопрос по этой теме и ответа так и не нашлось, поэтому сделал через RakNet. Что касается задержек, то программист, к сожалению, время выворачивать не может, если задача требует паузы между действиями (а таких задач 50% на практике), то никуда тут не деться, потоками, таймерами или колбэками всё равно придётся добиваться задержки.

А вот про первое ты как раз вообще не прав. Как программист решает, как решить задачу, а не задача решает, как код программисту решить.
и что же за РПЦ ты там эмулируешь, что ловишь такие артефакты?)
Тебе вон выше дали хорошую либу для таймеров. Ты в ГТА вообще забудь про слово поток. Это крайне плохая практика в этом сегменте.
Вот тебе еще одна
По поводу таймера. Правильно ли я понял, что вот эта функция в timer_manager::add_timer сработает как надо только если цикл будет постоянно бегать по ней? Допустим есть основной цикл с !timer_manager::process() и есть функция (допустим ввод команды в игре), которая отрабатывает один раз, в этой функции будет timer_manager::add_timer, оно сработает в таком случае или add_timer нужно вызывать каждую миллисекунду?
 
Последнее редактирование: