/*
**	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/>.
*/

/***********************************************************************************************
 ***                            Confidential - Westwood Studios                              ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Commando                                                     *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Commando/pkthandlers.cpp                      $*
 *                                                                                             *
 *                      $Author:: Steve_t                                                     $*
 *                                                                                             *
 *                     $Modtime:: 1/18/02 11:33a                                              $*
 *                                                                                             *
 *                    $Revision:: 53                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "cnetwork.h"

#include "debug.h"
#include "networkobjectmgr.h"
#include "networkobjectfactory.h"
#include "networkobjectfactorymgr.h"
#include "playermanager.h"
#include "apppacketstats.h"
#include "specialbuilds.h"


extern char * Addr_As_String(sockaddr_in *addr);
extern bool g_is_loading;

//-----------------------------------------------------------------------------
NetworkObjectClass *
Create_Network_Object (cPacket &packet, int class_id, int network_obj_id)
{
	WWASSERT(network_obj_id > 0);

	//
	//	Lookup the factory for this type of network object
	//
	NetworkObjectFactoryClass *factory = NetworkObjectFactoryMgrClass::Find_Factory (class_id);
	WWASSERT (factory != NULL);

	//
	//	Create the new object
	//
	NetworkObjectClass *new_object = factory->Create (packet);
	WWASSERT (new_object != NULL);

	new_object->Set_Network_ID(network_obj_id);//TSS2001b

	return new_object;
}

//-----------------------------------------------------------------------------
void cNetwork::Server_Packet_Handler(cPacket & packet, int rhost_id)
{
#ifndef BETACLIENT

	WWASSERT(I_Am_Server());
	WWASSERT(
		rhost_id >= PServerConnection->Get_Min_RHost() &&
		rhost_id <= PServerConnection->Get_Max_RHost());
	WWASSERT(Receiver != NULL);

	/*TSS082801
	// TSS - hack
	if (g_is_loading) {
		Debug_Say(("Server flushing packet during loading\n"));
		packet.Flush();
		return;
	}
	*/

	//
	// TSS112401 XXX
	//
	if (PServerConnection->Get_Remote_Host(rhost_id) == NULL) {
		//
		// We were getting this crash:
		// pkthandlers.cpp (95) - received BIT_CREATION for existing object of type
		// APPPACKETTYPE_CSDAMAGEEVENT following messages "Insufficient bandwidth to send all guaranteed packets".
		//
		// The only scenario I can envisage is that the server destroys a client, but
		// some damage packets are on the wire. Then a new client joins, gets the same client_id,
		// and sends some damage packets with the same id's.
		//
		WWDEBUG_SAY(("cNetwork::Server_Packet_Handler: flushing packet from invalid rhost_id %d\n",
			rhost_id));

		packet.Flush();
		return;
	}

	int network_obj_id		= packet.Get (network_obj_id);
	BYTE dirty_bits			= packet.Get (dirty_bits);
	bool is_delete_pending	= packet.Get (is_delete_pending);

	//
	//	Lookup the object this data belongs to
	//
	NetworkObjectClass *object = NetworkObjectMgrClass::Find_Object (network_obj_id);

	//
	//	Do we need to create this object?
	//
	if ((dirty_bits & NetworkObjectClass::BIT_CREATION) == NetworkObjectClass::BIT_CREATION) {

		int net_classid = packet.Get (net_classid);

		//WWASSERT (object == NULL);
		if (object != NULL)
		{
#ifdef WWDEBUG
			//sockaddr_in *actual_from_addr_ptr = (LPSOCKADDR_IN) &packet.Get_From_Address_Wrapper()->FromAddress;
			//sockaddr_in rhost_addr = PServerConnection->Get_Remote_Host(rhost_id)->Get_Address();
#endif //WWDEBUG

//#pragma message("(TSS) APPPACKETTYPE_CSDAMAGEEVENT workaround for unknown crash bug.\n")

			//WWDEBUG_SAY(("\n"));
			//WWDEBUG_SAY(("cNetwork::Server_Packet_Handler: received BIT_CREATION (id %d, is_delete_pending = %d, net_classid = %d, from rhost %d - %s) for existing object:\n",
			//	network_obj_id, is_delete_pending, net_classid, rhost_id, Addr_As_String(&rhost_addr)));
			//WWDEBUG_SAY(("  id                 = %d\n", object->Get_Network_ID()));
			//WWDEBUG_SAY(("  AppPacketType      = %s\n", cAppPacketStats::Interpret_Type(object->Get_App_Packet_Type())));
			//WWDEBUG_SAY(("  IsDeletePending    = %d\n", object->Is_Delete_Pending()));
			//WWDEBUG_SAY(("  CreatedByPacketID  = %d\n", object->Get_Created_By_Packet_ID()));
			//WWDEBUG_SAY(("Packet actually from address %s\n", Addr_As_String(actual_from_addr_ptr)));
			//WWDEBUG_SAY(("\n"));

			//DIE;

			//
			// So far we've only seen the problem manifest for APPPACKETTYPE_CSDAMAGEEVENT.
			// It should be safe to kill the existing conflicting object of this type.
			//
			if (object->Get_App_Packet_Type() == APPPACKETTYPE_CSDAMAGEEVENT) {
				object->Set_Delete_Pending();
			}

			//
			// Flush this packet and bail.
			//
			packet.Flush();
			return;
		}

		//
		//	Create the network object
		//
		object = Create_Network_Object (packet, net_classid, network_obj_id);
#ifdef WWDEBUG
		object->Set_Created_By_Packet_ID(packet.Get_Id());
#endif //WWDEBUG
		object->Import_Creation (packet);

		/*
		//XXX
		WWDEBUG_SAY(("Created object # %-3d of type %-20s and id %d\n",
			NetworkObjectMgrClass::Get_Object_Count(),
			cAppPacketStats::Interpret_Type(object->Get_App_Packet_Type()),
			network_obj_id));
		*/
	}

	//
	// TSS092301
	//
	if (PServerConnection->Get_Remote_Host(rhost_id) == NULL) {
		//
		// This was probably a quit packet. Bail !
		//
		packet.Flush();
		return;
	}

	if (object != NULL) {

		//
		//	Do we need to modify this object?
		//
		if ((dirty_bits & NetworkObjectClass::BIT_RARE) == NetworkObjectClass::BIT_RARE) {
			object->Import_Rare (packet);
		}

		//
		//	Do we need to modify this object?
		//
		if ((dirty_bits & NetworkObjectClass::BIT_OCCASIONAL) == NetworkObjectClass::BIT_OCCASIONAL) {
			object->Import_Occasional (packet);
		}

		//
		//	Do we need to update this object?
		//
		if ((dirty_bits & NetworkObjectClass::BIT_FREQUENT) == NetworkObjectClass::BIT_FREQUENT) {
			object->Import_Frequent (packet);
			//object->Increment_Import_State_Count ();
		}

		object->Increment_Import_State_Count();

		//
		//	Do we need to delete this object?
		//
		if (is_delete_pending) {

			//
			//	Delete the object
			//
			if (object != NULL) {
				object->Set_Delete_Pending ();
			}
		}
	} else {
		packet.Flush();
		//Debug_Network_Basic(("Server received update for non-existent object %d.\n",
		//	network_obj_id));
	}

	//
	//	Did we read all the data contained in the packet?
	//
	//WWASSERT(packet.Is_Flushed());
	if (!packet.Is_Flushed())
	{
		WWDEBUG_SAY(("cNetwork::Client_Packet_Handler: packet not flushed for object of type %s\n",
			cAppPacketStats::Interpret_Type(object->Get_App_Packet_Type())));
		DIE;
	}

#endif // not BETACLIENT
}

//-----------------------------------------------------------------------------
void cNetwork::Client_Packet_Handler(cPacket & packet)
{
#ifndef FREEDEDICATEDSERVER

	WWASSERT(I_Am_Client());
	WWASSERT(Receiver != NULL);

	// TSS - hack
	if (g_is_loading) {
		Debug_Say(("Client flushing packet during loading\n"));
		packet.Flush();
		return;
	}

	//
	// This is presently needed for team object creation which isn't filtered out on send
	//
	if (cNetwork::I_Am_Server()) {
		packet.Flush ();
		return;
	}

	int network_obj_id		= packet.Get (network_obj_id);
	BYTE dirty_bits			= packet.Get (dirty_bits);
	bool is_delete_pending	= packet.Get (is_delete_pending);
	//BYTE app_packet_type		= packet.Get (app_packet_type);

	//
	//	Lookup the object this data belongs to
	//
	NetworkObjectClass *object = NetworkObjectMgrClass::Find_Object (network_obj_id);

	//
	//	Do we need to create this object?
	//
	if ((dirty_bits & NetworkObjectClass::BIT_CREATION) == NetworkObjectClass::BIT_CREATION) {

		//WWASSERT (object == NULL);
		if (object != NULL)
		{
			WWDEBUG_SAY(("cNetwork::Client_Packet_Handler: received BIT_CREATION for existing object of type %s\n",
				cAppPacketStats::Interpret_Type(object->Get_App_Packet_Type())));
			DIE;
		}

		//
		//	Create the network object
		//
		int net_classid = packet.Get (net_classid);
		if (object == NULL) {
			object = Create_Network_Object (packet, net_classid, network_obj_id);
		}
		object->Import_Creation (packet);

		//
		//	HACK - HACK
		//
		if (net_classid == NETCLASSID_GAMEOBJ) {
			BaseGameObj *game_obj			= (BaseGameObj *)object;
			SmartGameObj *smart_game_obj	= game_obj->As_SmartGameObj ();
			if (smart_game_obj != NULL) {
				int control_owner = smart_game_obj->Get_Control_Owner ();
				smart_game_obj->Set_Player_Data (cPlayerManager::Find_Player (control_owner));
			}
		}

		/*
		//XXX
		WWDEBUG_SAY(("Created object # %-3d of type %-20s and id %d\n",
			NetworkObjectMgrClass::Get_Object_Count(),
			cAppPacketStats::Interpret_Type(object->Get_App_Packet_Type()),
			network_obj_id));
		*/
	}

	if (object != NULL) {

		//
		//	Do we need to delete this object?
		//
		if (is_delete_pending && object != NULL) {
			object->Set_Delete_Pending ();
		}

		//
		//	Do we need to modify this object?
		//
		if ((dirty_bits & NetworkObjectClass::BIT_RARE) == NetworkObjectClass::BIT_RARE) {
			object->Import_Rare (packet);
		}

		//
		//	Do we need to modify this object?
		//
		if ((dirty_bits & NetworkObjectClass::BIT_OCCASIONAL) == NetworkObjectClass::BIT_OCCASIONAL) {
			object->Import_Occasional (packet);
		}

		//
		//	Do we need to update this object?
		//
		if ((dirty_bits & NetworkObjectClass::BIT_FREQUENT) == NetworkObjectClass::BIT_FREQUENT) {
			object->Import_Frequent (packet);
			//object->Increment_Import_State_Count ();
		}

		object->Increment_Import_State_Count();
		object->Set_Last_Clientside_Update_Time(TIMEGETTIME());

		/*moving up
		//
		//	Do we need to delete this object?
		//
		if (is_delete_pending) {

			//
			//	Delete the object
			//
			if (object != NULL) {
				object->Set_Delete_Pending ();
			}
		}
		*/
	} else {
		packet.Flush();
		//Debug_Network_Basic(("Client %d received update for non-existent object %d.\n",
		//	Get_My_Id(), network_obj_id));
	}

	//
	//	Did we read all the data contained in the packet?
	//
	//WWASSERT(packet.Is_Flushed());
	if (!packet.Is_Flushed())
	{
		WWDEBUG_SAY(("cNetwork::Client_Packet_Handler: packet not flushed for object of type %s\n",
			cAppPacketStats::Interpret_Type(object->Get_App_Packet_Type())));
		//DIE;
	}

#endif // !FREEDEDICATEDSERVER
}







	//BYTE app_packet_type		= packet.Get (app_packet_type);