Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
441 lines
11 KiB
C++
441 lines
11 KiB
C++
#include "munga.h"
|
|
#pragma hdrstop
|
|
|
|
#include "hostmgr.h"
|
|
#include "interest.h"
|
|
#include "icom.h"
|
|
#include "app.h"
|
|
#include "notation.h"
|
|
#include "nttmgr.h"
|
|
|
|
#if defined(TRACE_ROUTE_PACKET)
|
|
static BitTrace Route_Packet("Route Packet");
|
|
# define SET_ROUTE_PACKET() Route_Packet.Set()
|
|
# define CLEAR_ROUTE_PACKET() Route_Packet.Clear()
|
|
#else
|
|
# define SET_ROUTE_PACKET()
|
|
# define CLEAR_ROUTE_PACKET()
|
|
#endif
|
|
|
|
const NetworkAddress NullNetworkAddress = 0x00000000;// 0.0.0.0 (in TCP land);
|
|
|
|
//#############################################################################
|
|
// Shared Data Support
|
|
//
|
|
NetworkClient::SharedData
|
|
NetworkClient::DefaultData(
|
|
NetworkClient::GetClassDerivations(),
|
|
NetworkClient::GetMessageHandlers()
|
|
);
|
|
|
|
//
|
|
//#############################################################################
|
|
// Code for the network client class
|
|
//#############################################################################
|
|
//
|
|
Derivation* NetworkClient::GetClassDerivations()
|
|
{
|
|
static Derivation classDerivations(Receiver::GetClassDerivations(), "NetworkClient");
|
|
return &classDerivations;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Constructor for the NetworkClient
|
|
//
|
|
NetworkClient::NetworkClient(
|
|
ClassID class_ID,
|
|
SharedData &virtual_data,
|
|
ClientID client_ID
|
|
):
|
|
Receiver(class_ID, virtual_data)
|
|
{
|
|
clientID = client_ID;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Destructor for the NetworkClient
|
|
//
|
|
NetworkClient::~NetworkClient()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Destructor for the NetworkClient
|
|
//
|
|
Logical
|
|
NetworkClient::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(*GetClassDerivations());
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Receive packet for the NetworkClient
|
|
//
|
|
void
|
|
NetworkClient::ReceiveNetworkPacket(
|
|
NetworkPacket*,
|
|
Receiver::Message *packet_message
|
|
)
|
|
{
|
|
Dispatch(packet_message);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Code for the network manager class
|
|
//#############################################################################
|
|
|
|
const Receiver::HandlerEntry
|
|
NetworkManager::MessageHandlerEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(NetworkManager,ReceiveEggFile)
|
|
};
|
|
|
|
Receiver::MessageHandlerSet& NetworkManager::GetMessageHandlers()
|
|
{
|
|
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(NetworkManager::MessageHandlerEntries), NetworkManager::MessageHandlerEntries, NetworkClient::GetMessageHandlers());
|
|
return messageHandlers;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
NetworkManager::SharedData
|
|
NetworkManager::DefaultData(
|
|
NetworkManager::GetClassDerivations(),
|
|
NetworkManager::GetMessageHandlers()
|
|
);
|
|
|
|
Derivation* NetworkManager::GetClassDerivations()
|
|
{
|
|
static Derivation classDerivations(NetworkClient::GetClassDerivations(), "NetworkManager");
|
|
return &classDerivations;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Constructor for the NetworkManager
|
|
//
|
|
NetworkManager::NetworkManager(SharedData &shared_data):
|
|
NetworkClient(NetworkManagerClassID, shared_data, NetworkManagerClientID)
|
|
{
|
|
// basic init goes here
|
|
gameID = 0;
|
|
addresses = NULL;
|
|
num_addresses = 0;
|
|
eggTempBuffer = NULL;
|
|
networkEggNotationFile = NULL;
|
|
eggTempNext = 0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Creates a host for us. Any derived class must deal with reading the
|
|
// notation file to get the network nodes to connect to. This start is
|
|
// designed for STAND-ALONE MODE ONLY and should not be inherited for use by
|
|
//
|
|
void
|
|
NetworkManager::StartConnecting(Mission *)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Make the local host, and get the application to adopt it
|
|
//---------------------------------------------------------
|
|
//
|
|
SOCKADDR_IN address;
|
|
address.sin_family = AF_INET;
|
|
address.sin_addr.S_un.S_addr = 1;
|
|
Host *local_host = new Host(1, GameMachineHostType, &address);
|
|
Register_Object(local_host);
|
|
|
|
Check(application);
|
|
Check(application->GetHostManager());
|
|
application->GetHostManager()->AdoptLocalHost(local_host);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Now, since this host creator is for stand-alone mode, send the load
|
|
// mission message to the application
|
|
//--------------------------------------------------------------------
|
|
//
|
|
Check(application);
|
|
Application::Message
|
|
load_message(
|
|
Application::LoadMissionMessageID,
|
|
sizeof(Application::Message)
|
|
);
|
|
application->Post(DefaultEventPriority, application, &load_message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::EndMission This routine is called when a mission ends to
|
|
// allow the network management system to do stuff (like disconnecting network
|
|
// connections between pods and so on)
|
|
//
|
|
Logical
|
|
NetworkManager::Shutdown()
|
|
{
|
|
//
|
|
// If there is a notation file floating about, kill it!
|
|
//
|
|
if (networkEggNotationFile)
|
|
{
|
|
Unregister_Object(networkEggNotationFile);
|
|
delete networkEggNotationFile;
|
|
}
|
|
|
|
//
|
|
// Deregister local host
|
|
//
|
|
Host *local_host;
|
|
|
|
local_host = application->GetHostManager()->OrphanLocalHost();
|
|
Unregister_Object(local_host);
|
|
delete local_host;
|
|
|
|
return True;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Destructor for the NetworkManager
|
|
//
|
|
NetworkManager::~NetworkManager()
|
|
{
|
|
// shutdown net goes here
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::ReceiveEggFileMessageHandler
|
|
//
|
|
void
|
|
NetworkManager::ReceiveEggFileMessageHandler(
|
|
ReceiveEggFileMessage* EggMessage
|
|
)
|
|
{
|
|
//
|
|
// An egg sequence number of -1 means that the egg is posted locally, and
|
|
// should just call create mission
|
|
//
|
|
if (EggMessage->sequenceNumber == -1)
|
|
{
|
|
application->CreateMission(networkEggNotationFile);
|
|
return;
|
|
}
|
|
|
|
if (EggMessage->sequenceNumber == 0)
|
|
{
|
|
//
|
|
// Make a buffer
|
|
//
|
|
eggTempBuffer = new char[EggMessage->notationFileLength];
|
|
Register_Pointer(eggTempBuffer);
|
|
eggTempNext = 0;
|
|
}
|
|
|
|
//
|
|
// Write the egg data into the buffer
|
|
//
|
|
memcpy(
|
|
(eggTempBuffer+eggTempNext),
|
|
EggMessage->notationData,
|
|
EggMessage->thisMessageLength
|
|
);
|
|
eggTempNext += EggMessage->thisMessageLength;
|
|
|
|
//
|
|
// If we don't have all the data, return and wait for more
|
|
//
|
|
if(eggTempNext < EggMessage->notationFileLength)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// We've got all the data, make the notation file
|
|
//
|
|
networkEggNotationFile = new NotationFile();
|
|
Register_Object(networkEggNotationFile);
|
|
networkEggNotationFile->ReadText(eggTempBuffer, eggTempNext);
|
|
networkEggNotationFile->WriteFile("last.egg");
|
|
|
|
//
|
|
// Now turn the notation file into a mission
|
|
//
|
|
application->CreateMission(networkEggNotationFile);
|
|
|
|
//
|
|
// Get rid of the ram buffer now that we're done with it
|
|
//
|
|
Unregister_Pointer(eggTempBuffer);
|
|
delete eggTempBuffer;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::Send Handles sending a message to a specific network address
|
|
// which can NOT be us. Default behavior is to do nothing, as no network is
|
|
// hooked up if we get here
|
|
//
|
|
void
|
|
NetworkManager::Send(
|
|
Message *,
|
|
ClientID,
|
|
HostID
|
|
)
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::Broadcast Handles broadcasting a message to everyone,
|
|
// including ourselves. !!!! Reliable broadcasting is currently used,
|
|
// implimented by sending a point-to-point message to every destination.
|
|
//
|
|
void
|
|
NetworkManager::Broadcast(
|
|
Message *message,
|
|
ClientID client_id
|
|
)
|
|
{
|
|
//
|
|
// Send this message back to ourselves
|
|
//
|
|
NetworkClient *client = GetNetworkClientPointer(client_id);
|
|
Check(client);
|
|
client->ReceiveNetworkPacket(NULL, message);
|
|
|
|
//
|
|
// Broadcast the message to everyone else on the network
|
|
//
|
|
ExclusiveBroadcast(message,client_id);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::ExclusiveBroadcast Broadcasts a message to everyone on the
|
|
// network execpt us. Default behavior sends it to nobody, as there is really
|
|
// no network
|
|
//
|
|
void
|
|
NetworkManager::ExclusiveBroadcast(
|
|
Message *,
|
|
ClientID
|
|
)
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::GetNetworkClientPointer Determine who the client of a
|
|
// message is and return a pointer to them.
|
|
//
|
|
NetworkClient*
|
|
NetworkManager::GetNetworkClientPointer(ClientID client_id)
|
|
{
|
|
switch (client_id)
|
|
{
|
|
case NetworkClient::NetworkManagerClientID:
|
|
return this;
|
|
|
|
case NetworkClient::EntityManagerClientID:
|
|
Check(application);
|
|
return application->GetEntityManager();
|
|
|
|
case NetworkClient::HostManagerClientID:
|
|
Check(application);
|
|
return application->GetHostManager();
|
|
|
|
case NetworkClient::InterestManagerClientID:
|
|
Check(application);
|
|
return application->GetInterestManager();
|
|
|
|
case NetworkClient::IcomManagerClientID:
|
|
Check(application);
|
|
return application->GetIntercomManager();
|
|
|
|
case NetworkClient::ApplicationClientID:
|
|
Check(application);
|
|
return application;
|
|
|
|
default:
|
|
DEBUG_STREAM << "------UNKNOWN NETWORK CLIENT ID " << client_id << std::endl << std::flush;
|
|
Fail("Unknown Client ID");
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::RoutePacket
|
|
//
|
|
Logical
|
|
NetworkManager::RoutePacket()
|
|
{
|
|
Check(this);
|
|
|
|
Byte
|
|
message_buffer[NETWORKMANAGER_BUFFER_SIZE];
|
|
NetworkPacket
|
|
*p;
|
|
|
|
//
|
|
// Return if check buffers doesn't have a packet for us
|
|
//
|
|
if (!CheckBuffers((NetworkPacket*)message_buffer))
|
|
{
|
|
return False;
|
|
}
|
|
|
|
//
|
|
// Process and route the packet properly
|
|
//
|
|
p = (NetworkPacket*)message_buffer;
|
|
|
|
if (p->gameID == gameID)
|
|
{
|
|
// cout<<"++++++++client "<<p->clientID<<" gameID "<<p->gameID<<" fromHost "<<p->fromHost<<"\n";
|
|
NetworkClient *client = GetNetworkClientPointer(p->clientID);
|
|
|
|
Check(client);
|
|
SET_ROUTE_PACKET();
|
|
client->ReceiveNetworkPacket(p, &p->messageData);
|
|
CLEAR_ROUTE_PACKET();
|
|
}
|
|
else
|
|
{
|
|
DEBUG_STREAM << "+++++++++ client " << p->clientID << " gameID " << p->gameID << " fromHost " << p->fromHost << std::endl << std::flush;
|
|
Fail("######### NOT A PACKET FOR THIS GAME!");
|
|
}
|
|
|
|
RemovePacket(p);
|
|
return True;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::ExecuteBackground Allows the network to perform tasks in
|
|
// the applications background. The method should return True if the manager
|
|
// is busy, false otherwise. For example, if the input and output buffers of
|
|
// the network driver are not empty then return True, otherwise return False.
|
|
//
|
|
Logical
|
|
NetworkManager::ExecuteBackground()
|
|
{
|
|
return True;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::CheckBuffers Checks to see if there is a message for us
|
|
// buffered up in the network interface card and returns a pointer to it.
|
|
//
|
|
Logical
|
|
NetworkManager::CheckBuffers(NetworkPacket*)
|
|
{
|
|
Fail("NetworkManager::CheckBuffers - should never reach here!");
|
|
return False;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager::RemovePacket If the network implimentation requires us to
|
|
// free up a packet buffer, this routine would do it.
|
|
//
|
|
void
|
|
NetworkManager::RemovePacket(NetworkPacket*)
|
|
{
|
|
Fail("NetworkManager::RemovePacket - should never reach here!");
|
|
}
|