CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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