lanchat.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. ** Command & Conquer Renegade(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. // Filename: lanchat.cpp
  20. // Project: Network.lib, for Commando
  21. // Author: Tom Spencer-Smith
  22. // Date: Dec 1998
  23. // Description: lan chat interface
  24. //
  25. // TODO:
  26. // - allow non-unique player names on the LAN
  27. // - no provision for graceless exit of person (must remove if don't hear from them)
  28. // - num players in a channel not shown
  29. //
  30. //-----------------------------------------------------------------------------
  31. #include "lanchat.h"
  32. #pragma warning(disable : 4201)
  33. #include "systimer.h"
  34. #include "wwdebug.h"
  35. #include "_globals.h"
  36. #include "netutil.h"
  37. #include "langmode.h"
  38. #include "cnetwork.h"
  39. #include "gamemode.h"
  40. #include "registry.h"
  41. #include "gamechanlist.h"
  42. #include "playermanager.h"
  43. #include "gametype.h"
  44. #include "translatedb.h"
  45. #include "string_ids.h"
  46. #include "fromaddress.h"
  47. #include "DlgMPConnect.h"
  48. #include "slavemaster.h"
  49. #include "dlgmpchangelannickname.h"
  50. #include "gamespyadmin.h"
  51. #include "demosupport.h"
  52. //
  53. // Class statics
  54. //
  55. const USHORT cLanChat::LAN_BROADCAST_INTERVAL_MS = 1000;
  56. #pragma message ("(TSS) BUMP LAN BCAST PORT FOR D1P")
  57. //const USHORT cLanChat::LAN_PORT = 0xEA00;
  58. const USHORT cLanChat::LAN_PORT = 3373;
  59. //-----------------------------------------------------------------------------
  60. cLanChat::cLanChat(void) :
  61. Socket(INVALID_SOCKET),
  62. LastPositionBroadcastTimeMs(0),
  63. PositionBroadcastNumber(0),
  64. CurrentLocation(LANLOC_LOBBY)
  65. {
  66. WWDEBUG_SAY(("cLanChat::cLanChat\n"));
  67. ZeroMemory(&Socket, sizeof(Socket));
  68. ZeroMemory(&LocalAddress, sizeof(LocalAddress));
  69. Load_Lan_Registry_Keys();
  70. Save_Lan_Registry_Keys();
  71. Init_Lan_Protocol_And_Socket();
  72. //cGameChannelList::Remove_All();
  73. }
  74. //-----------------------------------------------------------------------------
  75. cLanChat::~cLanChat(void)
  76. {
  77. WWDEBUG_SAY(("cLanChat::~cLanChat\n"));
  78. Save_Lan_Registry_Keys();
  79. if (Socket != INVALID_SOCKET) {
  80. cNetUtil::Close_Socket(Socket);
  81. }
  82. }
  83. //-----------------------------------------------------------------------------
  84. void cLanChat::Load_Lan_Registry_Keys(void)
  85. {
  86. WWDEBUG_SAY(("cLanChat::Load_Lan_Registry_Keys\n"));
  87. RegistryClass * registry = new RegistryClass(APPLICATION_SUB_KEY_NAME_NETOPTIONS);
  88. WWASSERT(registry);
  89. WWASSERT(registry->Is_Valid());
  90. char name[200];
  91. registry->Get_String("MyLanName", name, sizeof(name), "");
  92. WideStringClass widename;
  93. widename.Convert_From(name);
  94. if (!cGameSpyAdmin::Is_Gamespy_Game()) {
  95. if (widename.Is_Empty())
  96. {
  97. cNetInterface::Set_Random_Nickname();
  98. }
  99. else
  100. {
  101. cNetInterface::Set_Nickname(widename);
  102. }
  103. }
  104. int sidePref = registry->Get_Int("SidePref", -1);
  105. cNetInterface::Set_Side_Preference(sidePref);
  106. delete registry;
  107. }
  108. //-----------------------------------------------------------------------------
  109. void cLanChat::Save_Lan_Registry_Keys(void)
  110. {
  111. WWDEBUG_SAY(("cLanChat::Save_Lan_Registry_Keys...\n"));
  112. RegistryClass * registry = new RegistryClass(APPLICATION_SUB_KEY_NAME_NETOPTIONS);
  113. WWASSERT(registry);
  114. WWASSERT(registry->Is_Valid());
  115. if (!cGameSpyAdmin::Is_Gamespy_Game()) {
  116. StringClass string;
  117. cNetInterface::Get_Nickname().Convert_To(string);
  118. registry->Set_String("MyLanName", string);
  119. }
  120. registry->Set_Int("SidePref", cNetInterface::Get_Side_Preference());
  121. delete registry;
  122. }
  123. //-----------------------------------------------------------------------------
  124. void cLanChat::Init_Lan_Protocol_And_Socket(void)
  125. {
  126. WWASSERT(!IS_SOLOPLAY);
  127. if (cGameSpyAdmin::Is_Gamespy_Game()) {
  128. return;
  129. }
  130. bool is_internet = false;
  131. if (!cNetUtil::Protocol_Init(is_internet)) {
  132. DIE;
  133. }
  134. //
  135. // Init socket
  136. //
  137. if (Socket != INVALID_SOCKET) {
  138. cNetUtil::Close_Socket(Socket);
  139. }
  140. bool succeeded = cNetUtil::Create_Bound_Socket(Socket, LAN_PORT, LocalAddress);
  141. WWASSERT(succeeded);
  142. }
  143. //-----------------------------------------------------------------------------
  144. void cLanChat::Accept_Actions(void)
  145. {
  146. DlgMPConnect::DoDialog(cNetInterface::Get_Side_Preference(), 0);
  147. }
  148. //-----------------------------------------------------------------------------
  149. void cLanChat::Refusal_Actions(void)
  150. {
  151. //
  152. // Must do this if join rejected
  153. //
  154. }
  155. //-----------------------------------------------------------------------------
  156. void cLanChat::Send_Position_Broadcast(void)
  157. {
  158. //GAMESPY
  159. if (cGameSpyAdmin::Is_Gamespy_Game()) {
  160. return;
  161. }
  162. //Debug_Say(("Send_Position_Broadcast\n"));
  163. if (TIMEGETTIME() - LastPositionBroadcastTimeMs > LAN_BROADCAST_INTERVAL_MS) {
  164. //
  165. // Everybody broadcasts their position periodically, as well as
  166. // immediately after changing location.
  167. //
  168. //
  169. // Broadcast number is used to decide who has to change their name if
  170. // there is a name collision. The first guy in wins out.
  171. //
  172. LastPositionBroadcastTimeMs = TIMEGETTIME();
  173. PositionBroadcastNumber++;
  174. cPacket packet;
  175. packet.Add((BYTE) LAN_MESSAGE_POSITION);
  176. packet.Add_Wide_Terminated_String(cNetInterface::Get_Nickname());
  177. packet.Add(PositionBroadcastNumber);
  178. bool is_hosting = cNetwork::I_Am_Server() &&
  179. GameModeManager::Find("Combat")->Is_Active();
  180. packet.Add(is_hosting);
  181. if (is_hosting) {
  182. WWASSERT(PTheGameData != NULL);
  183. packet.Add((int) The_Game()->Get_Game_Type());
  184. The_Game()->Export_Tier_1_Data(packet);
  185. }
  186. cNetUtil::Broadcast(Socket, LAN_PORT, packet);
  187. }
  188. }
  189. //-----------------------------------------------------------------------------
  190. void cLanChat::Process_Position_Broadcast(cPacket & packet)
  191. {
  192. //Debug_Say(("Process_Position_Broadcast\n"));
  193. WideStringClass sender;
  194. packet.Get_Wide_Terminated_String(sender.Get_Buffer(256), 256);
  195. int broadcast_number = packet.Get(broadcast_number);
  196. bool is_hosting = packet.Get(is_hosting);
  197. //if (sender == cNetInterface::Get_Nickname() &&
  198. if (!sender.Compare_No_Case(cNetInterface::Get_Nickname()) &&
  199. broadcast_number > PositionBroadcastNumber) {
  200. packet.Flush();
  201. WWDEBUG_SAY(("*** LAN NICKNAME COLLISION (%s) ***\n", sender));
  202. DlgMpChangeLanNickname::DoDialog();
  203. return;
  204. }
  205. if (is_hosting) {
  206. int game_type = packet.Get(game_type);
  207. cGameData * p_game_data = cGameData::Create_Game_Of_Type(
  208. (cGameData::GameTypeEnum) game_type);
  209. WWASSERT(p_game_data != NULL);
  210. p_game_data->Import_Tier_1_Data(packet);
  211. /*
  212. //
  213. // TSS2001f
  214. // Manually correct hosting ip address according to recv address
  215. //
  216. WWASSERT(packet.Get_From_Address_Wrapper() != NULL);
  217. p_game_data->Set_Ip_Address(packet.Get_From_Address_Wrapper()->FromAddress.sin_addr.s_addr);
  218. WWDEBUG_SAY(("Manually setting ip to %s\n",
  219. cNetUtil::Address_To_String(p_game_data->Get_Ip_Address())));
  220. */
  221. //
  222. // Don't add this game to the channel list if the player doesn't
  223. // have the map locally
  224. //
  225. if (p_game_data->Does_Map_Exist ()) {
  226. cGameChannelList::Add_Channel(p_game_data);
  227. } else {
  228. delete p_game_data;
  229. p_game_data = NULL;
  230. }
  231. } else {
  232. cGameChannelList::Remove_Channel(sender);
  233. //Debug_Say(("Removing channel for %s\n", sender));
  234. }
  235. }
  236. //-----------------------------------------------------------------------------
  237. void cLanChat::Lan_Packet_Handler(cPacket & packet)
  238. {
  239. //GAMESPY
  240. if (cGameSpyAdmin::Is_Gamespy_Game()) {
  241. packet.Flush();
  242. return;
  243. }
  244. if (CurrentLocation == LANLOC_EXIT) {
  245. //
  246. // Ignore our own broadcasts
  247. //
  248. packet.Flush();
  249. } else {
  250. BYTE packet_type = packet.Get(packet_type);
  251. switch (packet_type) {
  252. case LAN_MESSAGE_POSITION:
  253. Process_Position_Broadcast(packet);
  254. break;
  255. default:
  256. WWDEBUG_SAY(("cLanChat::Lan_Packet_Handler: received bogus packet_type (%d)\n", packet_type));
  257. //DIE;
  258. packet.Flush();
  259. break;
  260. }
  261. }
  262. }
  263. //-----------------------------------------------------------------------------
  264. static void External_Lan_Packet_Handler(cPacket & packet)
  265. {
  266. //WWASSERT(LanGameModeClass::PLanChat != NULL);
  267. PLC->Lan_Packet_Handler(packet);
  268. }
  269. //-----------------------------------------------------------------------------
  270. void cLanChat::Go_To_Location(ChatLocationEnum location)
  271. {
  272. CurrentLocation = location;
  273. }
  274. //-----------------------------------------------------------------------------
  275. void cLanChat::Think(void)
  276. {
  277. if (cGameSpyAdmin::Is_Gamespy_Game()) {
  278. return;
  279. }
  280. if (CurrentLocation != LANLOC_EXIT) {
  281. Send_Position_Broadcast();
  282. cNetUtil::Lan_Servicing(Socket, External_Lan_Packet_Handler);
  283. DEMO_SECURITY_CHECK;
  284. }
  285. }
  286. /*
  287. if (MPLanGameListMenuClass::Get_Instance() != NULL) {
  288. MPLanGameListMenuClass::Get_Instance()->Set_Is_Name_Colliding();
  289. }
  290. */
  291. //MPLanGameListMenuClass::Set_Is_Name_Colliding();
  292. //#include "dlgmplangamelist.h"
  293. //cHelpText::Set(TRANSLATION(IDS_MP_NICKNAME_IN_USE));
  294. //WWDEBUG_SAY(("*** LAN NICKNAME COLLISION (%s) ***\n", sender));
  295. /*
  296. if (!cNetInterface::Is_Valid_Name(name)) {
  297. cNetInterface::Set_Random_Nickname();
  298. ::strcpy(name, cNetInterface::Get_Nickname());
  299. }
  300. */