389 lines
9.4 KiB
C++
389 lines
9.4 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Filename: lanchat.cpp
|
||
|
// Project: Network.lib, for Commando
|
||
|
// Author: Tom Spencer-Smith
|
||
|
// Date: Dec 1998
|
||
|
// Description: lan chat interface
|
||
|
//
|
||
|
// TODO:
|
||
|
// - allow non-unique player names on the LAN
|
||
|
// - no provision for graceless exit of person (must remove if don't hear from them)
|
||
|
// - num players in a channel not shown
|
||
|
//
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
#include "lanchat.h"
|
||
|
|
||
|
#pragma warning(disable : 4201)
|
||
|
#include "systimer.h"
|
||
|
|
||
|
#include "wwdebug.h"
|
||
|
#include "_globals.h"
|
||
|
#include "netutil.h"
|
||
|
#include "langmode.h"
|
||
|
#include "cnetwork.h"
|
||
|
#include "gamemode.h"
|
||
|
#include "registry.h"
|
||
|
#include "gamechanlist.h"
|
||
|
#include "playermanager.h"
|
||
|
#include "gametype.h"
|
||
|
#include "translatedb.h"
|
||
|
#include "string_ids.h"
|
||
|
#include "fromaddress.h"
|
||
|
#include "DlgMPConnect.h"
|
||
|
#include "slavemaster.h"
|
||
|
#include "dlgmpchangelannickname.h"
|
||
|
#include "gamespyadmin.h"
|
||
|
#include "demosupport.h"
|
||
|
|
||
|
//
|
||
|
// Class statics
|
||
|
//
|
||
|
const USHORT cLanChat::LAN_BROADCAST_INTERVAL_MS = 1000;
|
||
|
#pragma message ("(TSS) BUMP LAN BCAST PORT FOR D1P")
|
||
|
//const USHORT cLanChat::LAN_PORT = 0xEA00;
|
||
|
const USHORT cLanChat::LAN_PORT = 3373;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
cLanChat::cLanChat(void) :
|
||
|
Socket(INVALID_SOCKET),
|
||
|
LastPositionBroadcastTimeMs(0),
|
||
|
PositionBroadcastNumber(0),
|
||
|
CurrentLocation(LANLOC_LOBBY)
|
||
|
{
|
||
|
WWDEBUG_SAY(("cLanChat::cLanChat\n"));
|
||
|
|
||
|
ZeroMemory(&Socket, sizeof(Socket));
|
||
|
ZeroMemory(&LocalAddress, sizeof(LocalAddress));
|
||
|
|
||
|
Load_Lan_Registry_Keys();
|
||
|
Save_Lan_Registry_Keys();
|
||
|
|
||
|
Init_Lan_Protocol_And_Socket();
|
||
|
|
||
|
//cGameChannelList::Remove_All();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
cLanChat::~cLanChat(void)
|
||
|
{
|
||
|
WWDEBUG_SAY(("cLanChat::~cLanChat\n"));
|
||
|
|
||
|
Save_Lan_Registry_Keys();
|
||
|
if (Socket != INVALID_SOCKET) {
|
||
|
cNetUtil::Close_Socket(Socket);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Load_Lan_Registry_Keys(void)
|
||
|
{
|
||
|
WWDEBUG_SAY(("cLanChat::Load_Lan_Registry_Keys\n"));
|
||
|
|
||
|
RegistryClass * registry = new RegistryClass(APPLICATION_SUB_KEY_NAME_NETOPTIONS);
|
||
|
WWASSERT(registry);
|
||
|
WWASSERT(registry->Is_Valid());
|
||
|
|
||
|
char name[200];
|
||
|
registry->Get_String("MyLanName", name, sizeof(name), "");
|
||
|
|
||
|
WideStringClass widename;
|
||
|
widename.Convert_From(name);
|
||
|
|
||
|
if (!cGameSpyAdmin::Is_Gamespy_Game()) {
|
||
|
if (widename.Is_Empty())
|
||
|
{
|
||
|
cNetInterface::Set_Random_Nickname();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cNetInterface::Set_Nickname(widename);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int sidePref = registry->Get_Int("SidePref", -1);
|
||
|
cNetInterface::Set_Side_Preference(sidePref);
|
||
|
|
||
|
delete registry;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Save_Lan_Registry_Keys(void)
|
||
|
{
|
||
|
WWDEBUG_SAY(("cLanChat::Save_Lan_Registry_Keys...\n"));
|
||
|
|
||
|
RegistryClass * registry = new RegistryClass(APPLICATION_SUB_KEY_NAME_NETOPTIONS);
|
||
|
WWASSERT(registry);
|
||
|
WWASSERT(registry->Is_Valid());
|
||
|
|
||
|
if (!cGameSpyAdmin::Is_Gamespy_Game()) {
|
||
|
StringClass string;
|
||
|
cNetInterface::Get_Nickname().Convert_To(string);
|
||
|
registry->Set_String("MyLanName", string);
|
||
|
}
|
||
|
|
||
|
registry->Set_Int("SidePref", cNetInterface::Get_Side_Preference());
|
||
|
|
||
|
delete registry;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Init_Lan_Protocol_And_Socket(void)
|
||
|
{
|
||
|
WWASSERT(!IS_SOLOPLAY);
|
||
|
if (cGameSpyAdmin::Is_Gamespy_Game()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool is_internet = false;
|
||
|
if (!cNetUtil::Protocol_Init(is_internet)) {
|
||
|
DIE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Init socket
|
||
|
//
|
||
|
if (Socket != INVALID_SOCKET) {
|
||
|
cNetUtil::Close_Socket(Socket);
|
||
|
}
|
||
|
|
||
|
bool succeeded = cNetUtil::Create_Bound_Socket(Socket, LAN_PORT, LocalAddress);
|
||
|
WWASSERT(succeeded);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Accept_Actions(void)
|
||
|
{
|
||
|
DlgMPConnect::DoDialog(cNetInterface::Get_Side_Preference(), 0);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Refusal_Actions(void)
|
||
|
{
|
||
|
//
|
||
|
// Must do this if join rejected
|
||
|
//
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Send_Position_Broadcast(void)
|
||
|
{
|
||
|
//GAMESPY
|
||
|
if (cGameSpyAdmin::Is_Gamespy_Game()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Debug_Say(("Send_Position_Broadcast\n"));
|
||
|
if (TIMEGETTIME() - LastPositionBroadcastTimeMs > LAN_BROADCAST_INTERVAL_MS) {
|
||
|
|
||
|
//
|
||
|
// Everybody broadcasts their position periodically, as well as
|
||
|
// immediately after changing location.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Broadcast number is used to decide who has to change their name if
|
||
|
// there is a name collision. The first guy in wins out.
|
||
|
//
|
||
|
LastPositionBroadcastTimeMs = TIMEGETTIME();
|
||
|
PositionBroadcastNumber++;
|
||
|
|
||
|
cPacket packet;
|
||
|
packet.Add((BYTE) LAN_MESSAGE_POSITION);
|
||
|
packet.Add_Wide_Terminated_String(cNetInterface::Get_Nickname());
|
||
|
packet.Add(PositionBroadcastNumber);
|
||
|
bool is_hosting = cNetwork::I_Am_Server() &&
|
||
|
GameModeManager::Find("Combat")->Is_Active();
|
||
|
packet.Add(is_hosting);
|
||
|
|
||
|
if (is_hosting) {
|
||
|
WWASSERT(PTheGameData != NULL);
|
||
|
packet.Add((int) The_Game()->Get_Game_Type());
|
||
|
The_Game()->Export_Tier_1_Data(packet);
|
||
|
}
|
||
|
|
||
|
cNetUtil::Broadcast(Socket, LAN_PORT, packet);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Process_Position_Broadcast(cPacket & packet)
|
||
|
{
|
||
|
//Debug_Say(("Process_Position_Broadcast\n"));
|
||
|
|
||
|
WideStringClass sender;
|
||
|
packet.Get_Wide_Terminated_String(sender.Get_Buffer(256), 256);
|
||
|
int broadcast_number = packet.Get(broadcast_number);
|
||
|
bool is_hosting = packet.Get(is_hosting);
|
||
|
|
||
|
//if (sender == cNetInterface::Get_Nickname() &&
|
||
|
if (!sender.Compare_No_Case(cNetInterface::Get_Nickname()) &&
|
||
|
broadcast_number > PositionBroadcastNumber) {
|
||
|
|
||
|
packet.Flush();
|
||
|
|
||
|
WWDEBUG_SAY(("*** LAN NICKNAME COLLISION (%s) ***\n", sender));
|
||
|
|
||
|
DlgMpChangeLanNickname::DoDialog();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (is_hosting) {
|
||
|
|
||
|
int game_type = packet.Get(game_type);
|
||
|
cGameData * p_game_data = cGameData::Create_Game_Of_Type(
|
||
|
(cGameData::GameTypeEnum) game_type);
|
||
|
WWASSERT(p_game_data != NULL);
|
||
|
p_game_data->Import_Tier_1_Data(packet);
|
||
|
|
||
|
/*
|
||
|
//
|
||
|
// TSS2001f
|
||
|
// Manually correct hosting ip address according to recv address
|
||
|
//
|
||
|
WWASSERT(packet.Get_From_Address_Wrapper() != NULL);
|
||
|
p_game_data->Set_Ip_Address(packet.Get_From_Address_Wrapper()->FromAddress.sin_addr.s_addr);
|
||
|
WWDEBUG_SAY(("Manually setting ip to %s\n",
|
||
|
cNetUtil::Address_To_String(p_game_data->Get_Ip_Address())));
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// Don't add this game to the channel list if the player doesn't
|
||
|
// have the map locally
|
||
|
//
|
||
|
if (p_game_data->Does_Map_Exist ()) {
|
||
|
cGameChannelList::Add_Channel(p_game_data);
|
||
|
} else {
|
||
|
delete p_game_data;
|
||
|
p_game_data = NULL;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
cGameChannelList::Remove_Channel(sender);
|
||
|
//Debug_Say(("Removing channel for %s\n", sender));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Lan_Packet_Handler(cPacket & packet)
|
||
|
{
|
||
|
//GAMESPY
|
||
|
if (cGameSpyAdmin::Is_Gamespy_Game()) {
|
||
|
packet.Flush();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (CurrentLocation == LANLOC_EXIT) {
|
||
|
//
|
||
|
// Ignore our own broadcasts
|
||
|
//
|
||
|
packet.Flush();
|
||
|
|
||
|
} else {
|
||
|
|
||
|
BYTE packet_type = packet.Get(packet_type);
|
||
|
|
||
|
switch (packet_type) {
|
||
|
|
||
|
case LAN_MESSAGE_POSITION:
|
||
|
Process_Position_Broadcast(packet);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
WWDEBUG_SAY(("cLanChat::Lan_Packet_Handler: received bogus packet_type (%d)\n", packet_type));
|
||
|
//DIE;
|
||
|
packet.Flush();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
static void External_Lan_Packet_Handler(cPacket & packet)
|
||
|
{
|
||
|
//WWASSERT(LanGameModeClass::PLanChat != NULL);
|
||
|
PLC->Lan_Packet_Handler(packet);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Go_To_Location(ChatLocationEnum location)
|
||
|
{
|
||
|
CurrentLocation = location;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void cLanChat::Think(void)
|
||
|
{
|
||
|
if (cGameSpyAdmin::Is_Gamespy_Game()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (CurrentLocation != LANLOC_EXIT) {
|
||
|
Send_Position_Broadcast();
|
||
|
cNetUtil::Lan_Servicing(Socket, External_Lan_Packet_Handler);
|
||
|
|
||
|
DEMO_SECURITY_CHECK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
if (MPLanGameListMenuClass::Get_Instance() != NULL) {
|
||
|
MPLanGameListMenuClass::Get_Instance()->Set_Is_Name_Colliding();
|
||
|
}
|
||
|
*/
|
||
|
//MPLanGameListMenuClass::Set_Is_Name_Colliding();
|
||
|
|
||
|
//#include "dlgmplangamelist.h"
|
||
|
//cHelpText::Set(TRANSLATION(IDS_MP_NICKNAME_IN_USE));
|
||
|
|
||
|
//WWDEBUG_SAY(("*** LAN NICKNAME COLLISION (%s) ***\n", sender));
|
||
|
/*
|
||
|
if (!cNetInterface::Is_Valid_Name(name)) {
|
||
|
cNetInterface::Set_Random_Nickname();
|
||
|
::strcpy(name, cNetInterface::Get_Nickname());
|
||
|
}
|
||
|
*/
|
||
|
|