MPMGRD.CPP (7185B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 #include "mpmgrd.h" 17 18 extern "C" { 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <assert.h> 23 #include "types.h" 24 #include "rtq.h" 25 #include "services.h" 26 } 27 #include "mplib.h" 28 #include "mplpc.h" 29 30 31 #define STATUS_OK 1 32 #define STATUS_BAD 0 33 34 #define BROADCAST_ADDR 0 35 36 typedef struct { 37 DWORD address; 38 char Data[1]; 39 } packet; 40 41 #define min(a,b) (((a) < (b)) ? (a) : (b)) 42 43 #define FREEQUEUE 0 44 #define DOSWORKQUEUE 1 45 #define WINWORKQUEUE 2 46 #define WINSENDQUEUE 3 47 #define DOSPENDINGQUEUE 4 48 #define WINWORKQUEUE2 5 49 50 // 6, 7, 8, taken up by LPC services 51 52 #define GDOSWORKQUEUE 14 53 #define GWINWORKQUEUE 15 54 #define GWINSENDQUEUE 16 55 #define GDOSPENDINGQUEUE 17 56 #define GWINWORKQUEUE2 18 57 58 MPlayerManClass::MPlayerManClass(void) : ConnManClass() 59 { 60 unsigned size; 61 62 MGenGetMasterNode(&size); 63 if (size != sizeof(RTQ_NODE)) { 64 exit(-234); 65 } 66 _myAddr = LPCGetMPAddr(); 67 _nConnections = 0; 68 69 for (int i = 0; i < CONNECT_MAX; i++) { 70 _Connections[i] = 0; 71 strcpy(_Names[i], ""); 72 } 73 } 74 75 // here's what we do to get private & broadcasts over the same chunnel 76 // we package up an extra dword at the beginning to indicate the address 77 78 int 79 MPlayerManClass::Send_Private_Message(void *buf, 80 int buflen, 81 int /* ack_req */, 82 int conn_id) 83 { 84 RTQ_NODE *n; 85 int idx = Connection_Index(conn_id); 86 87 if (_nConnections == 0) { 88 return (STATUS_OK); 89 } 90 91 while ((n = MGenMoveTo(FREEQUEUE, DOSWORKQUEUE)) == 0); 92 93 packet *p = (packet *) n->rtqDatum; 94 95 if (conn_id == CONNECTION_NONE) { 96 p->address = BROADCAST_ADDR; 97 } else { 98 p->address = _Connections[idx]; 99 } 100 101 memcpy(p->Data, buf, buflen); 102 n->rtqUpCtr = (WORD)(buflen + sizeof(DWORD)); 103 104 MGenMoveTo(DOSWORKQUEUE, WINSENDQUEUE); 105 PostWindowsMessage(); 106 Yield(); 107 108 return STATUS_OK; 109 } 110 111 int 112 MPlayerManClass::Get_Private_Message(void *buf, int *buflen, 113 int *conn_id) 114 { 115 RTQ_NODE *n; 116 int i; 117 118 if ((n = MGenMoveTo(DOSPENDINGQUEUE, DOSWORKQUEUE)) == 0) { 119 *buflen = 0; 120 return 0; 121 } 122 123 packet *p = (packet *) n->rtqDatum; 124 125 int lentocpy = n->rtqUpCtr - sizeof(DWORD); 126 127 *conn_id = CONNECTION_NONE; 128 for (i = 0; i < _nConnections; i++) { 129 if (p->address == _Connections[i]) { 130 (*conn_id) = _ID[i]; 131 break; 132 } 133 } 134 135 memcpy(buf, p->Data, lentocpy); 136 137 *buflen = lentocpy; 138 139 MGenMoveTo(DOSWORKQUEUE, FREEQUEUE); 140 141 return STATUS_OK; 142 } 143 144 int 145 MPlayerManClass::Send_Global_Message(void *buf, int buflen, int /*ack_req*/, 146 int address) 147 { 148 RTQ_NODE *n; 149 150 while ((n = MGenMoveTo(FREEQUEUE, DOSWORKQUEUE)) == 0); 151 152 packet *p = (packet *) n->rtqDatum; 153 154 if (address == 0) { 155 p->address = BROADCAST_ADDR; 156 } else { 157 p->address = address; 158 } 159 160 memcpy(p->Data, buf, buflen); 161 n->rtqUpCtr = (WORD)(buflen + sizeof(DWORD)); 162 163 MGenMoveTo(DOSWORKQUEUE, GWINSENDQUEUE); 164 PostWindowsMessage(); 165 Yield(); 166 167 return STATUS_OK; 168 } 169 170 int 171 MPlayerManClass::Get_Global_Message(void *buf, int *buflen, int *address) 172 { 173 RTQ_NODE *n; 174 175 if ((n = MGenMoveTo(GDOSPENDINGQUEUE, DOSWORKQUEUE)) == 0) { 176 *buflen = 0; 177 return 0; 178 } 179 180 packet *p = (packet *) n->rtqDatum; 181 182 int lentocpy = n->rtqUpCtr - sizeof(DWORD); 183 184 if (address) { 185 if (p->address == BROADCAST_ADDR) { 186 *address = 0; 187 } else { 188 *address = p->address; 189 } 190 } 191 192 memcpy(buf, p->Data, lentocpy); 193 194 *buflen = lentocpy; 195 196 MGenMoveTo(DOSWORKQUEUE, FREEQUEUE); 197 198 return STATUS_OK; 199 } 200 201 int 202 MPlayerManClass::Service(void) 203 { 204 return STATUS_OK; 205 } 206 207 int 208 MPlayerManClass::Create_Connection(int id, char *name, int address) 209 { 210 _Connections[_nConnections] = address; 211 _ID[_nConnections] = id; 212 strcpy(_Names[_nConnections], name); 213 _nConnections++; 214 return STATUS_OK; 215 } 216 217 int 218 MPlayerManClass::Delete_Connection(int id) 219 { 220 int i; 221 int idx = Connection_Index(id); 222 if (idx == -1) 223 return 0; 224 225 for (i = idx; i < _nConnections - 1; i++) { 226 _Connections[i] = _Connections[i+1]; 227 _ID[i] = _ID[i+1]; 228 strcpy (_Names[i], _Names[i+1]); 229 } 230 _nConnections--; 231 return STATUS_OK; 232 } 233 234 char * 235 MPlayerManClass::Connection_Name(int id) 236 { 237 int idx = Connection_Index(id); 238 if (idx==-1) { 239 return (NULL); 240 } 241 242 return _Names[idx]; 243 } 244 245 int 246 MPlayerManClass::Connection_Address(int id) 247 { 248 int idx = Connection_Index(id); 249 if (idx==-1) { 250 return (0); 251 } 252 253 return _Connections[idx]; 254 } 255 256 int 257 MPlayerManClass::Num_Connections(void) 258 { 259 return _nConnections; 260 } 261 262 int 263 MPlayerManClass::Connection_ID(int index) 264 { 265 return _ID[index]; 266 } 267 268 int 269 MPlayerManClass::Connection_Index(int id) 270 { 271 int i; 272 273 for (i = 0; i < _nConnections; i++) { 274 if (_ID[i] == id) { 275 return i; 276 } 277 } 278 279 return -1; 280 } 281 282 int 283 MPlayerManClass::Global_Num_Send(void) 284 { 285 return 0; 286 } 287 288 int 289 MPlayerManClass::Global_Num_Receive(void) 290 { 291 return MGenGetQueueCtr(GDOSPENDINGQUEUE); 292 } 293 294 int 295 MPlayerManClass::Private_Num_Send(int /*id*/) 296 { 297 return 0; 298 } 299 300 int 301 MPlayerManClass::Private_Num_Receive(int /*id*/) 302 { 303 return MGenGetQueueCtr(DOSPENDINGQUEUE); 304 } 305 306 void 307 MPlayerManClass::Reset_Response_Time(void) 308 { 309 // unsupported 310 } 311 312 unsigned long 313 MPlayerManClass::Response_Time(void) 314 { 315 return (160 * 60) / 1000; // 160 microseconds one way (9 ticks) 316 } 317 318 void 319 MPlayerManClass::Set_Timing(unsigned long /*retrydelta*/, 320 unsigned long /*maxretries*/, 321 unsigned long /*timeout*/) 322 { 323 // unsupported 324 } 325 326 void 327 MPlayerManClass::Configure_Debug(int /*index*/, int /*type_offset*/, 328 int /*type_size*/, char ** /*names*/, 329 int /*namestart*/, int /*namecount*/) 330 { 331 // unsupported 332 } 333 334 void 335 MPlayerManClass::Mono_Debug_Print(int /*index*/, int /*refresh*/) 336 { 337 // unsupported 338 } 339 340 int 341 MPlayerManClass::Init(void) 342 { 343 return STATUS_OK; 344 } 345 346 int MPlayerManClass::Find_Num_Connections(void) 347 { 348 TGAMEDEF game_def; 349 int sz = sizeof(game_def); 350 351 GetGameDef(&game_def, &sz); 352 353 return (game_def.numPlayers - 1); 354 355 } 356 357 358 void MPlayerManClass::Flush_All(void) 359 { 360 MGenFlushNodes(DOSPENDINGQUEUE, FREEQUEUE); 361 MGenFlushNodes(GDOSPENDINGQUEUE, FREEQUEUE); 362 } 363