@ -4,18 +4,37 @@
* Implementation of functions for updating game state from network commands .
*/
# include <list>
# include <atomic>
# include <mutex>
# include "nthread.h"
# include "storm/storm.h"
# include "utils/sdl_mutex .h"
# include "utils/thread.h"
namespace devilution {
struct DThreadPkt {
int pnum ;
_cmd_id cmd ;
std : : unique_ptr < byte [ ] > data ;
uint32_t len ;
DThreadPkt ( int pnum , _cmd_id ( cmd ) , std : : unique_ptr < byte [ ] > data , uint32_t len )
: pnum ( pnum )
, cmd ( cmd )
, data ( std : : move ( data ) )
, len ( len )
{
}
} ;
namespace {
CCritSect sgMemCrit ;
SdlMutex DthreadMutex ;
SDL_threadID glpDThreadId ;
TMegaPkt * sgpInfoHead ; /* may not be right struct */
bool dthread_running ;
std : : list < DThreadPkt > InfoList ;
std : : atomic_ bool dthread_running ;
event_emul * sghWorkToDoEvent ;
/* rdata */
@ -23,37 +42,21 @@ SDL_Thread *sghThread = nullptr;
void DthreadHandler ( )
{
const char * errorBuf ;
TMegaPkt * pkt ;
DWORD dwMilliseconds ;
while ( dthread_running ) {
if ( sgpInfoHead = = nullptr & & WaitForEvent ( sghWorkToDoEvent ) = = - 1 ) {
errorBuf = SDL_GetError ( ) ;
app_fatal ( " dthread4: \n %s " , errorBuf ) ;
}
if ( InfoList . empty ( ) & & WaitForEvent ( sghWorkToDoEvent ) = = - 1 )
app_fatal ( " dthread4: \n %s " , SDL_GetError ( ) ) ;
sgMemCrit . Enter ( ) ;
pkt = sgpInfoHead ;
if ( sgpInfoHead ! = nullptr )
sgpInfoHead = sgpInfoHead - > pNext ;
else
DthreadMutex . lock ( ) ;
if ( InfoList . empty ( ) ) {
ResetEvent ( sghWorkToDoEvent ) ;
sgMemCrit . Leave ( ) ;
if ( pkt ! = nullptr ) {
if ( pkt - > dwSpaceLeft ! = MAX_PLRS )
multi_send_zero_packet ( pkt - > dwSpaceLeft , static_cast < _cmd_id > ( pkt - > data [ 0 ] ) , & pkt - > data [ 8 ] , * ( DWORD * ) & pkt - > data [ 4 ] ) ;
dwMilliseconds = 1000 * * ( DWORD * ) & pkt - > data [ 4 ] / gdwDeltaBytesSec ;
if ( dwMilliseconds > = 1 )
dwMilliseconds = 1 ;
std : : free ( pkt ) ;
if ( dwMilliseconds ! = 0 )
SDL_Delay ( dwMilliseconds ) ;
DthreadMutex . unlock ( ) ;
continue ;
}
DThreadPkt pkt = std : : move ( InfoList . front ( ) ) ;
InfoList . pop_front ( ) ;
DthreadMutex . unlock ( ) ;
multi_send_zero_packet ( pkt . pnum , pkt . cmd , pkt . data . get ( ) , pkt . len ) ;
}
}
@ -61,74 +64,38 @@ void DthreadHandler()
void dthread_remove_player ( uint8_t pnum )
{
TMegaPkt * pkt ;
sgMemCrit . Enter ( ) ;
for ( pkt = sgpInfoHead ; pkt ! = nullptr ; pkt = pkt - > pNext ) {
if ( pkt - > dwSpaceLeft = = pnum )
pkt - > dwSpaceLeft = MAX_PLRS ;
}
sgMemCrit . Leave ( ) ;
std : : lock_guard < SdlMutex > lock ( DthreadMutex ) ;
InfoList . remove_if ( [ & ] ( auto & pkt ) {
return pkt . pnum = = pnum ;
} ) ;
}
void dthread_send_delta ( int pnum , _cmd_id cmd , byte * pbSrc , int dwL en)
void dthread_send_delta ( int pnum , _cmd_id cmd , std : : unique_ptr < byte [ ] > data , uint32_t len )
{
TMegaPkt * pkt ;
TMegaPkt * p ;
if ( ! gbIsMultiplayer ) {
if ( ! gbIsMultiplayer )
return ;
}
pkt = static_cast < TMegaPkt * > ( std : : malloc ( dwLen + 20 ) ) ;
if ( pkt = = nullptr )
app_fatal ( " Failed to allocate memory " ) ;
pkt - > pNext = nullptr ;
pkt - > dwSpaceLeft = pnum ;
pkt - > data [ 0 ] = static_cast < byte > ( cmd ) ;
* ( DWORD * ) & pkt - > data [ 4 ] = dwLen ;
memcpy ( & pkt - > data [ 8 ] , pbSrc , dwLen ) ;
sgMemCrit . Enter ( ) ;
p = ( TMegaPkt * ) & sgpInfoHead ;
while ( p - > pNext ! = nullptr ) {
p = p - > pNext ;
}
p - > pNext = pkt ;
DThreadPkt pkt { pnum , cmd , std : : move ( data ) , len } ;
std : : lock_guard < SdlMutex > lock ( DthreadMutex ) ;
InfoList . push_back ( std : : move ( pkt ) ) ;
SetEvent ( sghWorkToDoEvent ) ;
sgMemCrit . Leave ( ) ;
}
void dthread_start ( )
{
const char * errorBuf ;
if ( ! gbIsMultiplayer ) {
if ( ! gbIsMultiplayer )
return ;
}
sghWorkToDoEvent = StartEvent ( ) ;
if ( sghWorkToDoEvent = = nullptr ) {
errorBuf = SDL_GetError ( ) ;
app_fatal ( " dthread:1 \n %s " , errorBuf ) ;
}
dthread_running = true ;
sghThread = CreateThread ( DthreadHandler , & glpDThreadId ) ;
if ( sghThread = = nullptr ) {
errorBuf = SDL_GetError ( ) ;
app_fatal ( " dthread2: \n %s " , errorBuf ) ;
}
}
void DThreadCleanup ( )
{
TMegaPkt * tmp ;
if ( sghWorkToDoEvent = = nullptr ) {
if ( sghWorkToDoEvent = = nullptr )
return ;
}
dthread_running = false ;
SetEvent ( sghWorkToDoEvent ) ;
@ -139,11 +106,7 @@ void DThreadCleanup()
EndEvent ( sghWorkToDoEvent ) ;
sghWorkToDoEvent = nullptr ;
while ( sgpInfoHead ! = nullptr ) {
tmp = sgpInfoHead - > pNext ;
std : : free ( sgpInfoHead ) ;
sgpInfoHead = tmp ;
}
InfoList . clear ( ) ;
}
} // namespace devilution