MPMGRD.CPP 7.0 KB

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