NetMessageStream.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. ** Command & Conquer Generals(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. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  24. // NetMessageStream.cpp
  25. // Holds misc functions to encapsulate GameMessages into Command Packets to send
  26. // over the network.
  27. // Author: Matthew D. Campbell, July 2001
  28. /*
  29. #include "stdlib.h" // VC++ wants this here, or gives compile error...
  30. #include "Common/GameType.h"
  31. #include "Common/MessageStream.h"
  32. #include "Common/GameEngine.h"
  33. #include "GameLogic/GameLogic.h"
  34. #include "GameNetwork/NetworkInterface.h"
  35. #include "GameNetwork/NetworkDefs.h"
  36. // The per-player pointers for the list of commands
  37. static CommandMsg *CommandHead[MAX_SLOTS] = { /// @todo: remove static initialization
  38. NULL,
  39. NULL,
  40. NULL,
  41. NULL,
  42. NULL,
  43. NULL,
  44. NULL,
  45. NULL
  46. };
  47. static CommandMsg *CommandTail[MAX_SLOTS] = {
  48. NULL,
  49. NULL,
  50. NULL,
  51. NULL,
  52. NULL,
  53. NULL,
  54. NULL,
  55. NULL
  56. };
  57. /**
  58. * AddToNetCommandList adds a CommandMsg to a list of commands.
  59. *
  60. static Bool AddToNetCommandList(GameMessage *msg, UnsignedInt timestamp, CommandMsg *& CommandHead, CommandMsg *& CommandTail)
  61. {
  62. CommandMsg *cmdMsg = NEW CommandMsg(timestamp, msg);
  63. if (!cmdMsg)
  64. {
  65. DEBUG_LOG(("Alloc failed!\n"));
  66. return false;
  67. }
  68. if (CommandTail == NULL)
  69. {
  70. CommandHead = cmdMsg;
  71. CommandTail = cmdMsg;
  72. }
  73. else
  74. {
  75. cmdMsg->SetPrevCommandMsg(CommandTail);
  76. CommandTail->SetNextCommandMsg(cmdMsg);
  77. CommandTail = cmdMsg;
  78. }
  79. return true;
  80. }
  81. /**
  82. * AddToRemoteNetCommandList is used by TheNetwork to queue up commands recieved from other players.
  83. *
  84. Bool AddToNetCommandList(Int playerNum, GameMessage *msg, UnsignedInt timestamp)
  85. {
  86. if (playerNum < 0 || playerNum >= MAX_SLOTS)
  87. return false;
  88. DEBUG_LOG(("Adding msg to NetCommandList %d\n", playerNum));
  89. return AddToNetCommandList(msg, timestamp, CommandHead[playerNum], CommandTail[playerNum]);
  90. }
  91. /**
  92. * GetCommandMsg returns a GameMessage (deleting its CommandMsg wrapper) that is valid
  93. * for the current frame, or NULL.
  94. *
  95. static GameMessage * GetCommandMsg(UnsignedInt timestamp, CommandMsg *& CommandHead, CommandMsg *& CommandTail)
  96. {
  97. if (!CommandHead)
  98. return NULL;
  99. if (CommandHead->GetTimestamp() < timestamp)
  100. {
  101. DEBUG_LOG(("Time is %d, yet message timestamp is %d!\n", timestamp, CommandHead->GetTimestamp()));
  102. return NULL;
  103. }
  104. if (CommandHead->GetTimestamp() != timestamp)
  105. return NULL;
  106. CommandMsg *theMsg = CommandHead;
  107. if (CommandHead->GetNextCommandMsg())
  108. {
  109. CommandHead->GetNextCommandMsg()->SetPrevCommandMsg(NULL);
  110. CommandHead = CommandHead->GetNextCommandMsg();
  111. }
  112. else
  113. {
  114. CommandHead = CommandTail = NULL;
  115. }
  116. GameMessage *msg = theMsg->GetGameMessage();
  117. delete theMsg;
  118. return msg;
  119. }
  120. /**
  121. * GetCommandMsg returns a message from the command list.
  122. *
  123. GameMessage * GetCommandMsg(UnsignedInt timestamp, Int playerNum)
  124. {
  125. if (playerNum < 0 || playerNum >= MAX_SLOTS)
  126. return NULL;
  127. //DEBUG_LOG(("Adding msg to NetCommandList %d\n", playerNum));
  128. return GetCommandMsg(timestamp, CommandHead[playerNum], CommandTail[playerNum]);
  129. }
  130. //====================================================================================
  131. // The commandBuf & commandPacket hold the commands we're building up for the frame.
  132. static unsigned char commandBuf[sizeof(CommandPacket)+1];
  133. static CommandPacket *commandPacket = (CommandPacket *)(commandBuf+1);
  134. /**
  135. * ClearCommandPacket clears the command packet at the start of the frame.
  136. *
  137. void ClearCommandPacket(UnsignedInt frame)
  138. {
  139. commandPacket->m_frame = frame;
  140. commandPacket->m_numCommands = 0;
  141. }
  142. /**
  143. * AddCommandToPacket creates a packet containing all move/attack/etc commands
  144. * for the current frame.
  145. *
  146. Bool AddCommandToPacket(const GameMessage *msg)
  147. {
  148. int messageSize = sizeofMessageHeader + sizeofMessageArg * msg->getArgumentCount();
  149. // If we have too much, send what we have
  150. if (bytesUsed && (bytesUsed + sizeof(CommandPacketHeader) + messageSize >= MAX_MESSAGE_LEN))
  151. {
  152. commandBuf[0] = MSGTYPE_PARTIALCOMMAND;
  153. if (!TheNetwork->queueSend(BROADCAST_CON, commandBuf, bytesUsed + sizeof(CommandPacketHeader) + 1, MSG_NEEDACK | MSG_SEQUENCED))
  154. {
  155. //DEBUG_ASSERTCRASH(false, ("Too many commands in one frame! Some will be dropped."));
  156. DEBUG_LOG(("Too many commands in one frame! Some will be dropped."));
  157. return false;
  158. }
  159. commandBuf[0] = MSGTYPE_COMMANDCOUNT;
  160. commandPacket->header.m_numCommands = 0;
  161. bytesUsed = 0;
  162. }
  163. if (bytesUsed + sizeof(CommandPacketHeader) + messageSize >= MAX_MESSAGE_LEN)
  164. {
  165. //DEBUG_ASSERTCRASH(false, ("Too many commands in one frame! Some will be dropped."));
  166. DEBUG_LOG(("Too many commands in one frame! Some will be dropped."));
  167. return false;
  168. }
  169. // We have room, so add the message
  170. commandPacket->header.m_numCommands++;
  171. commandPacket->m_commands[bytesUsed++] = (unsigned char)msg->getType();
  172. commandPacket->m_commands[bytesUsed++] = msg->getArgumentCount();
  173. for (int i=0; i<msg->getArgumentCount(); ++i)
  174. {
  175. memcpy((unsigned char *)(commandPacket->m_commands + bytesUsed), (unsigned char *)msg->getArgument(i), sizeofMessageArg);
  176. bytesUsed += sizeofMessageArg;
  177. }
  178. //DEBUG_ASSERTCRASH(bytesUsed + sizeof(CommandPacketHeader) < MAX_MESSAGE_LEN, ("Memory overwrite constructing command packet!"));
  179. //DEBUG_LOG(("Memory overwrite constructing command packet!"));
  180. return true;
  181. }
  182. /**
  183. * TheNetwork calls GetCommandPacket to get commands to send.
  184. *
  185. CommandPacket *GetCommandPacket(void)
  186. {
  187. commandBuf[0] = MSGTYPE_COMMANDCOUNT;
  188. return commandPacket;
  189. }
  190. //====================================================================================
  191. */