Devilution
Diablo devolved - magic behind the 1996 computer game
nthread.cpp
Go to the documentation of this file.
1 
6 #include "all.h"
7 #include "../3rdParty/Storm/Source/storm.h"
8 
10 
13 static CCritSect sgMemCrit;
17 uintptr_t glpMsgTbl[MAX_PLRS];
18 SDL_threadID glpNThreadId;
27 
28 /* data */
29 static SDL_Thread *sghThread = NULL;
30 
31 void nthread_terminate_game(const char *pszFcn)
32 {
33  DWORD sErr;
34 
35  sErr = SErrGetLastError();
36  if (sErr == STORM_ERROR_INVALID_PLAYER) {
37  return;
38  } else if (sErr == STORM_ERROR_GAME_TERMINATED) {
39  gbGameDestroyed = TRUE;
40  } else if (sErr == STORM_ERROR_NOT_IN_GAME) {
41  gbGameDestroyed = TRUE;
42  } else {
43  app_fatal("%s:\n%s", pszFcn, TraceLastError());
44  }
45 }
46 
47 DWORD nthread_send_and_recv_turn(DWORD cur_turn, int turn_delta)
48 {
49  DWORD new_cur_turn;
50  int turn, turn_tmp;
51  int curTurnsInTransit;
52 
53  new_cur_turn = cur_turn;
54  if (!SNetGetTurnsInTransit(&curTurnsInTransit)) {
55  nthread_terminate_game("SNetGetTurnsInTransit");
56  return 0;
57  }
58  while (curTurnsInTransit < gdwTurnsInTransit) {
59  curTurnsInTransit++;
60 
61  turn_tmp = turn_upper_bit | new_cur_turn & 0x7FFFFFFF;
62  turn_upper_bit = 0;
63  turn = turn_tmp;
64 
65  if (!SNetSendTurn((char *)&turn, sizeof(turn))) {
66  nthread_terminate_game("SNetSendTurn");
67  return 0;
68  }
69 
70  new_cur_turn += turn_delta;
71  if (new_cur_turn >= 0x7FFFFFFF)
72  new_cur_turn &= 0xFFFF;
73  }
74  return new_cur_turn;
75 }
76 
77 BOOL nthread_recv_turns(BOOL *pfSendAsync)
78 {
79  *pfSendAsync = FALSE;
81  if (sgbPacketCountdown) {
82  last_tick += 50;
83  return TRUE;
84  }
87  if (sgbSyncCountdown != 0) {
88 
89  *pfSendAsync = TRUE;
90  last_tick += 50;
91  return TRUE;
92  }
93  if (!SNetReceiveTurns(0, MAX_PLRS, (char **)glpMsgTbl, gdwMsgLenTbl, (LPDWORD)player_state)) {
94  if (SErrGetLastError() != STORM_ERROR_NO_MESSAGES_WAITING)
95  nthread_terminate_game("SNetReceiveTurns");
96  sgbTicsOutOfSync = FALSE;
97  sgbSyncCountdown = 1;
99  return FALSE;
100  } else {
101  if (!sgbTicsOutOfSync) {
102  sgbTicsOutOfSync = TRUE;
103  last_tick = SDL_GetTicks();
104  }
105  sgbSyncCountdown = 4;
107  *pfSendAsync = TRUE;
108  last_tick += 50;
109  return TRUE;
110  }
111 }
112 
114 {
115  turn_upper_bit = 0x80000000;
116 }
117 
118 void nthread_start(BOOL set_turn_upper_bit)
119 {
120  const char *err, *err2;
121  DWORD largestMsgSize;
122  _SNETCAPS caps;
123 
124  last_tick = SDL_GetTicks();
125  sgbPacketCountdown = 1;
126  sgbSyncCountdown = 1;
127  sgbTicsOutOfSync = TRUE;
128  if (set_turn_upper_bit)
130  else
131  turn_upper_bit = 0;
132  caps.size = 36;
133  if (!SNetGetProviderCaps(&caps)) {
134  err = TraceLastError();
135  app_fatal("SNetGetProviderCaps:\n%s", err);
136  }
138  if (!caps.defaultturnsintransit)
139  gdwTurnsInTransit = 1;
140  if (caps.defaultturnssec <= 20 && caps.defaultturnssec)
141  sgbNetUpdateRate = 20 / caps.defaultturnssec;
142  else
143  sgbNetUpdateRate = 1;
144  largestMsgSize = 512;
145  if (caps.maxmessagesize < 0x200)
146  largestMsgSize = caps.maxmessagesize;
147  gdwDeltaBytesSec = caps.bytessec >> 2;
148  gdwLargestMsgSize = largestMsgSize;
150  gdwNormalMsgSize *= 3;
151  gdwNormalMsgSize >>= 2;
152  if (caps.maxplayers > MAX_PLRS)
153  caps.maxplayers = MAX_PLRS;
155  while (gdwNormalMsgSize < 0x80) {
156  gdwNormalMsgSize *= 2;
157  sgbNetUpdateRate *= 2;
158  }
159  if (gdwNormalMsgSize > largestMsgSize)
160  gdwNormalMsgSize = largestMsgSize;
161  if (gbMaxPlayers > 1) {
162  sgbThreadIsRunning = FALSE;
163  sgMemCrit.Enter();
164  nthread_should_run = TRUE;
165  sghThread = CreateThread(nthread_handler, &glpNThreadId);
166  if (sghThread == NULL) {
167  err2 = TraceLastError();
168  app_fatal("nthread2:\n%s", err2);
169  }
170  }
171 }
172 
173 unsigned int nthread_handler(void *data)
174 {
175  int delta;
176  BOOL received;
177 
178  if (nthread_should_run) {
179  while (1) {
180  sgMemCrit.Enter();
181  if (!nthread_should_run)
182  break;
184  if (nthread_recv_turns(&received))
185  delta = last_tick - SDL_GetTicks();
186  else
187  delta = 50;
188  sgMemCrit.Leave();
189  if (delta > 0)
190  SDL_Delay(delta);
191  if (!nthread_should_run)
192  return 0;
193  }
194  sgMemCrit.Leave();
195  }
196  return 0;
197 }
198 
200 {
201  nthread_should_run = FALSE;
202  gdwTurnsInTransit = 0;
203  gdwNormalMsgSize = 0;
204  gdwLargestMsgSize = 0;
205  if (sghThread != NULL && glpNThreadId != SDL_GetThreadID(NULL)) {
206  if (!sgbThreadIsRunning)
207  sgMemCrit.Leave();
208  SDL_WaitThread(sghThread, NULL);
209  sghThread = NULL;
210  }
211 }
212 
213 void nthread_ignore_mutex(BOOL bStart)
214 {
215  if (sghThread != NULL) {
216  if (bStart)
217  sgMemCrit.Leave();
218  else
219  sgMemCrit.Enter();
220  sgbThreadIsRunning = bStart;
221  }
222 }
223 
224 BOOL nthread_has_500ms_passed(BOOL unused)
225 {
226  DWORD currentTickCount;
227  int ticksElapsed;
228 
229  currentTickCount = SDL_GetTicks();
230  ticksElapsed = currentTickCount - last_tick;
231  if (gbMaxPlayers == 1 && ticksElapsed > 500) {
232  last_tick = currentTickCount;
233  ticksElapsed = 0;
234  }
235  return ticksElapsed >= 0;
236 }
237 
_SNETCAPS::size
DWORD size
Definition: structs.h:1255
sgbSyncCountdown
char sgbSyncCountdown
Definition: nthread.cpp:19
gdwNormalMsgSize
DWORD gdwNormalMsgSize
Definition: nthread.cpp:25
MAX_PLRS
#define MAX_PLRS
Definition: defs.h:16
nthread_ignore_mutex
void nthread_ignore_mutex(BOOL bStart)
Definition: nthread.cpp:213
_SNETCAPS::bytessec
DWORD bytessec
Definition: structs.h:1260
sgbTicsOutOfSync
BOOLEAN sgbTicsOutOfSync
Definition: nthread.cpp:21
glpMsgTbl
uintptr_t glpMsgTbl[MAX_PLRS]
Definition: nthread.cpp:17
multi_msg_countdown
void multi_msg_countdown()
Definition: multi.cpp:178
nthread_send_and_recv_turn
DWORD nthread_send_and_recv_turn(DWORD cur_turn, int turn_delta)
Definition: nthread.cpp:47
gdwMsgLenTbl
DWORD gdwMsgLenTbl[MAX_PLRS]
Definition: nthread.cpp:12
sgMemCrit
static CCritSect sgMemCrit
Definition: nthread.cpp:13
gdwTurnsInTransit
DWORD gdwTurnsInTransit
Definition: nthread.cpp:16
all.h
sgbPacketCountdown
char sgbPacketCountdown
Definition: nthread.cpp:22
nthread_start
void nthread_start(BOOL set_turn_upper_bit)
Definition: nthread.cpp:118
gbMaxPlayers
BYTE gbMaxPlayers
Specifies the maximum number of players in a game, where 1 represents a single player game and 4 repr...
Definition: multi.cpp:34
turn_upper_bit
int turn_upper_bit
Definition: nthread.cpp:20
gbGameDestroyed
BOOLEAN gbGameDestroyed
Definition: multi.cpp:22
app_fatal
void app_fatal(const char *pszFmt,...)
Definition: appfat.cpp:18
DEVILUTION_END_NAMESPACE
#define DEVILUTION_END_NAMESPACE
Definition: types.h:10
nthread_has_500ms_passed
BOOL nthread_has_500ms_passed(BOOL unused)
Definition: nthread.cpp:224
sgbNetUpdateRate
DEVILUTION_BEGIN_NAMESPACE BYTE sgbNetUpdateRate
Definition: nthread.cpp:11
_SNETCAPS::maxplayers
DWORD maxplayers
Definition: structs.h:1259
nthread_terminate_game
void nthread_terminate_game(const char *pszFcn)
Definition: nthread.cpp:31
player_state
int player_state[MAX_PLRS]
Definition: multi.cpp:39
_SNETCAPS::defaultturnssec
DWORD defaultturnssec
Definition: structs.h:1262
sghThread
static SDL_Thread * sghThread
Definition: nthread.cpp:29
glpNThreadId
SDL_threadID glpNThreadId
Definition: nthread.cpp:18
_SNETCAPS
Definition: structs.h:1254
_SNETCAPS::maxmessagesize
DWORD maxmessagesize
Definition: structs.h:1257
last_tick
int last_tick
Definition: nthread.cpp:26
nthread_set_turn_upper_bit
void nthread_set_turn_upper_bit()
Definition: nthread.cpp:113
nthread_cleanup
void nthread_cleanup()
Definition: nthread.cpp:199
sgbThreadIsRunning
BOOLEAN sgbThreadIsRunning
Definition: nthread.cpp:23
nthread_recv_turns
BOOL nthread_recv_turns(BOOL *pfSendAsync)
Definition: nthread.cpp:77
_SNETCAPS::defaultturnsintransit
DWORD defaultturnsintransit
Definition: structs.h:1263
nthread_should_run
BOOLEAN nthread_should_run
Definition: nthread.cpp:15
gdwLargestMsgSize
DWORD gdwLargestMsgSize
Definition: nthread.cpp:24
nthread_handler
unsigned int nthread_handler(void *data)
Definition: nthread.cpp:173
DEVILUTION_BEGIN_NAMESPACE
Definition: sha.cpp:10
TraceLastError
#define TraceLastError
Definition: appfat.h:15
gdwDeltaBytesSec
DWORD gdwDeltaBytesSec
Definition: nthread.cpp:14