PDA

Просмотр полной версии : Задержка


Smeruxa
20.08.2021, 20:16
Пишу СФ плагин и вопрос, отправляю сообщение в чат но проблема, как сделать задержку между ними? Если использовать функции популярные то игру тупо фризит до тех пор пока все сообщения не отправятся

legendabrn
20.08.2021, 20:32
std::this_thread::sleep_for(std::chrono::milliseco nds(100)); // 100 миллисекунд

но перед этим создай поток что бы не зафризило игру:

Код:






std::thread test([]()
{
//code
};

test.detach();




или же:



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

Example:






#include
#include
#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
(
100
ms
)
;
}
unsigned
int
counter
=
0
;
while
(
true
)
{
pChat
->
AddMessage
(
-
1
,
(
std
::
string
(
"Hello "
)
+
std
::
to_string
(
counter
)
)
.
c_str
(
)
)
;
counter
++
;
this_coro
::
wait
(
1
s
)
;
}
}
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

(
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!

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

GitHub - allwanttokissme/coro_wait: Suspending coroutines by time (https://github.com/allwanttokissme/coro_wait)

Suspending coroutines by time. Contribute to allwanttokissme/coro_wait development by creating an account on GitHub.

github.com


хуки (https://github.com/allwanttokissme/Yet-another-hook-library)
sampapi (https://github.com/BlastHackNet/SAMP-API)

Smeruxa
20.08.2021, 20:49
std::this_thread::sleep_for(std::chrono::milliseco nds(100)); // 100 миллисекунд
но перед этим создай поток что бы не зафризило игру:

Код:






std::thread test([]()
{
//code
};

test.detach();




или же:


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

Dark_Knight
20.08.2021, 20:49
@Smeruxa (https://www.blast.hk/members/422424/)

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

Ya Zaregalsya
01.09.2021, 15:21
@Smeruxa (https://www.blast.hk/members/422424/)
первый вариант хуета, а второй заебись. потоки лучше юзать в крайне редких случаях, когда действия в главном цикле игры могут так нихуево грузить систему в момент исполнения кода, если этот код не прям нужный, то можно юзать их. Для всех остальных случаев лучше использовать таймеры.


Можно подробнее насчёт таймеров? Я использую функцию CreateThread, с ней вроде нет никаких проблем по части производительности даже когда таких потоков очень много.

Dark_Knight
01.09.2021, 20:37
Можно подробнее насчёт таймеров? Я использую функцию CreateThread, с ней вроде нет никаких проблем по части производительности даже когда таких потоков очень много.


Потоки зло. Они тебя сожрут, а так без кода ничего и не скажешь.

Ya Zaregalsya
02.09.2021, 03:16
Потоки зло. Они тебя сожрут, а так без кода ничего и не скажешь.


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

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


Код правильно писать. Задержки вообще плохая практика.

Ya Zaregalsya
02.09.2021, 18:25
Код правильно писать. Задержки вообще плохая практика.


Так себе совет, если честно. Придётся дальше на потоках сидеть.

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


@Dark_Knight (https://www.blast.hk/members/34/), наверное, говорит про написание DLL библиотек, где создание потоков и взаимодействие с памятью приложения может вызвать UB, к примеру из-за одновременного изменения того же участка памяти, так как это будет довольно сложно предотвратить. В создание самостоятельной программы, в использование потоков я не вижу ничего плохого, но надо уметь с ними работать чтобы не происходили возможные проблемы с ними.

UPD: Собственно надо и правильно понимать когда использование потоков востребовано, а когда можно обойтись без него.

Ya Zaregalsya
02.09.2021, 19:18
@Dark_Knight (https://www.blast.hk/members/34/), наверное, говорит про написание DLL библиотек, где создание потоков и взаимодействие с памятью приложения может вызвать UB, к примеру из-за одновременного изменения того же участка памяти, так как это будет довольно сложно предотвратить. В создание самостоятельной программы, в использование потоков я не вижу ничего плохого, но надо уметь с ними работать чтобы не происходили возможные проблемы с ними.


Dark Knight просто немножко чепуху задвигает, потому что это не программист решает, что ему нужна задержка, а в основном так просто стоит задача. Часто сталкиваюсь с UB, например вот артефакты и странные зависания при эмуляции входящих RPC в потоке:

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

kin4stat
02.09.2021, 19:55
Корутины


Либо что-то типа такого

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
02.09.2021, 20:19
Либо что-то типа такого

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
03.09.2021, 02:48
потому что это не программист решает, что ему нужна задержка, а в основном так просто стоит задача.


А вот про первое ты как раз вообще не прав. Как программист решает, как решить задачу, а не задача решает, как код программисту решить.

и что же за РПЦ ты там эмулируешь, что ловишь такие артефакты?)

Тебе вон выше дали хорошую либу для таймеров. Ты в ГТА вообще забудь про слово поток. Это крайне плохая практика в этом сегменте.

Вот тебе еще одна

GitHub - skyformat99/TimerManager: Crossplatform library for simple working with timers (https://github.com/skyformat99/TimerManager)

Crossplatform library for simple working with timers - skyformat99/TimerManager

github.com

Ya Zaregalsya
03.09.2021, 03:37
А вот про первое ты как раз вообще не прав. Как программист решает, как решить задачу, а не задача решает, как код программисту решить.
и что же за РПЦ ты там эмулируешь, что ловишь такие артефакты?)
Тебе вон выше дали хорошую либу для таймеров. Ты в ГТА вообще забудь про слово поток. Это крайне плохая практика в этом сегменте.
Вот тебе еще одна

GitHub - skyformat99/TimerManager: Crossplatform library for simple working with timers (https://github.com/skyformat99/TimerManager)

Crossplatform library for simple working with timers - skyformat99/TimerManager

github.com



На видео эмуляция различных RPC для установки позиции и направления камеры, их всего пять примерно, когда-то задавал вопрос по этой теме (https://www.blast.hk/threads/83191/) и ответа так и не нашлось, поэтому сделал через RakNet. Что касается задержек, то программист, к сожалению, время выворачивать не может, если задача требует паузы между действиями (а таких задач 50% на практике), то никуда тут не деться, потоками, таймерами или колбэками всё равно придётся добиваться задержки.



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

GitHub - skyformat99/TimerManager: Crossplatform library for simple working with timers (https://github.com/skyformat99/TimerManager)

Crossplatform library for simple working with timers - skyformat99/TimerManager

github.com



По поводу таймера. Правильно ли я понял, что вот эта функция в timer_manager::add_timer сработает как надо только если цикл будет постоянно бегать по ней? Допустим есть основной цикл с !timer_manager::process() и есть функция (допустим ввод команды в игре), которая отрабатывает один раз, в этой функции будет timer_manager::add_timer, оно сработает в таком случае или add_timer нужно вызывать каждую миллисекунду?