MPMGRD.CPP 6.9 KB

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