Files
TeslaRel410/restoration/source410/MUNGA_L4/L4NET.CPP
T
CydandClaude Fable 5 0906d1efa6 4.10 reconstruction: real l4net standalone path + full BTL4Mission::SetPlayerData
Boot ladder progress (each step verified live under DOSBox-X + 32RTM):

- L4NET.CPP v2: real statics (ClassDerivations/MessageHandlers/DefaultData),
  real single-user ctor (egg NotationFile -> last.egg -> local ReceiveEggFile
  post), real StartConnecting/Shutdown/CreateConsoleHost single-user branches,
  all four message handlers (egg assembly, ack, host connect/disconnect),
  1995 netnub-guard idiom (Net_Common_Ptr NULL => benign return) throughout;
  netnub wire primitives remain Fail-staged.  Sources: BT411 engine/MUNGA_L4/
  L4NET.cpp (preserves the 1995 netnub code as comments beside its Winsock
  port) cross-checked against the surviving 1995 L4NET.HPP.
- BTL4MSSN.CPP: full SetPlayerData reconstruction (vehicle/dropzone/color/
  patch/badge/team/experience/advancedDamage/role + score modifiers + plasma
  badge blit), backdated from BT411's Ghidra-recovered body (@004d2c30);
  every API pinned to the surviving 1995 headers (NOTATION/MISSION/SCNROLE/
  L4GREND/BTMSSN).

Boot now runs: banner -> resource load -> app ctor chain -> network manager
single-user init -> egg dispatch -> mission creation -> SetPlayerData (parses
the real TEST.EGG) -> halts at BTPlayer ctor (next staged brick).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:57:04 -05:00

748 lines
20 KiB
C++

//===========================================================================//
// File: l4net.cpp //
// Project: MUNGA Brick: Network Manager //
// Contents: Implementation details for the L4 network manager //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 03/02/95 GAC Initial coding. //
// 04/08/95 GAC Netnow Removed, TCP/NetNub support added //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <mungal4.hpp>
#pragma hdrstop
#if !defined(L4NET_HPP)
# include <l4net.hpp>
#endif
#if !defined(L4APP_HPP)
# include <l4app.hpp>
#endif
#if !defined(L4HOST_HPP)
# include <l4host.hpp>
#endif
#if !defined(MISSION_HPP)
# include <mission.hpp>
#endif
#if !defined(NOTATION_HPP)
# include <notation.hpp>
#endif
//
//#############################################################################
// NetNub client-side globals. Net_Common_Ptr NULL = no NetNub TSR loaded;
// L4File then takes its plain-DOS path (L4FILE.CPP:32) and the network
// manager runs in single user mode.
//#############################################################################
//
Netcom_Ptr
Net_Common_Ptr = NULL;
void
NetNub::SendCommand()
{
Fail("NetNub::SendCommand -- netnub interface not yet reconstructed");
}
//
//#############################################################################
// Shared data support
//#############################################################################
//
Derivation
L4NetworkManager::ClassDerivations(
NetworkManager::ClassDerivations,
"L4NetworkManager"
);
const Receiver::HandlerEntry
L4NetworkManager::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(L4NetworkManager,ReceiveEggFile),
MESSAGE_ENTRY(L4NetworkManager,AcknowledgeEggFile),
MESSAGE_ENTRY(L4NetworkManager,HostConnected),
MESSAGE_ENTRY(L4NetworkManager,HostDisconnected)
};
L4NetworkManager::MessageHandlerSet
L4NetworkManager::MessageHandlers(
ELEMENTS(L4NetworkManager::MessageHandlerEntries),
L4NetworkManager::MessageHandlerEntries,
NetworkManager::MessageHandlers
);
L4NetworkManager::SharedData
L4NetworkManager::DefaultData(
L4NetworkManager::ClassDerivations,
L4NetworkManager::MessageHandlers
);
//
//#############################################################################
// Code for the network manager class
//#############################################################################
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the L4NetworkManager
//
L4NetworkManager::L4NetworkManager():
NetworkManager(DefaultData),
messageBuffer(this)
{
unsigned long
network_common_flat_address;
network_common_flat_address =
L4Application::GetNetworkCommonFlatAddress();
lastHostIteratorPosition = 0;
nextOpenHostID = FirstLegalHostID+1; // Reserve first legal id for console
currentNetworkState = NormalState;
myConsoleHost = NULL;
eggAcknowledged = False;
networkStartupMode = SlaveMode;
numberOfMungaHostsConnected = 0;
numberOfConsoleHostsConnected = 0;
remoteHostCount = 0x7FFFFFFF;
//
// If there is no net common, set things up for single user mode
//
if (network_common_flat_address == 0)
{
Net_Common_Ptr = NULL;
//
//---------------------------------------------------------------------
// Retrieve the egg as specified on the command line, and send it as an
// egg message
//---------------------------------------------------------------------
//
CString egg_name = L4Application::GetEggNotationFileName();
if (!strlen(egg_name))
{
Fail("ERROR: No source exists for egg!");
}
networkEggNotationFile = new NotationFile(egg_name);
Register_Object(networkEggNotationFile);
networkEggNotationFile->WriteFile("last.egg");
currentNetworkState = NormalState;
ReceiveEggFileMessage egg_message(-1, 10, "local egg", 10);
application->Post(DefaultEventPriority, this, &egg_message);
return;
}
//
// Setup the local netcom structure and some pointers to things inside it
//
Fail("L4NetworkManager -- netnub (networked) path not yet reconstructed");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4NetworkManager::~L4NetworkManager()
{
if (networkEggNotationFile)
{
Unregister_Object(networkEggNotationFile);
delete networkEggNotationFile;
networkEggNotationFile = NULL;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::CreateConsoleHost This routine creates the console remote
// host and posts a listen for the console connection.
//
void
L4NetworkManager::CreateConsoleHost()
{
//
// Die if there is no network common around
//
if (Net_Common_Ptr == NULL)
{
return;
}
//
// Initialize a bunch of stuff to sane states
//
nextOpenHostID = FirstLegalHostID+1; // Reserve first legal id for console
networkStartupMode = SlaveMode; // We're a slave, (not a simulated console)
currentNetworkState = ConsoleOnly; // Only accept messages from the console
numberOfConsoleHostsConnected = 0; // Shouldn't be any consoles yet
numberOfMungaHostsConnected = 0; // No game machines either
Fail("L4NetworkManager::CreateConsoleHost -- netnub path not yet reconstructed");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::StartConnecting This routine is called when a mission
// starts to allow the network management system to establish communications
// with all the participants.
//
void
L4NetworkManager::StartConnecting(Mission *mission)
{
L4Host *my_l4host;
//
// This should be entered with no network connections to other game hosts
// up, so we initialize this count to zero.
//
numberOfMungaHostsConnected = 0;
//
// Create the host iterator for the mission egg
//
Mission::HostIterator mission_host_iterator(mission);
MissionHostData *mission_host_data;
//
// If there is no net common, set things up for single user mode
//
if (Net_Common_Ptr == NULL)
{
//
// Make the local host for single user testing, we give the host ID#1
// and assign the first symbolic name in the egg to it.
//
mission_host_data = mission_host_iterator.ReadAndNext();
Check(mission_host_data);
my_l4host = new L4Host(
1, // Host ID
mission_host_data->GetHostType(), // Host Type
NullNetworkAddress, // Net Address
0, // Socket address
mission_host_data->GetAddressString()
);
Register_Object(my_l4host);
Check(application);
Check(application->GetHostManager());
application->GetHostManager()->AdoptLocalHost(my_l4host);
//
//--------------------------------------------------------------------
// 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);
return;
}
Fail("L4NetworkManager::StartConnecting -- netnub path not yet reconstructed");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Shutdown This routine is called when a mission ends to
// allow the network management system to drop all the connections.
//
Logical
L4NetworkManager::Shutdown()
{
Host
*base_host;
L4Host
*my_l4host;
unsigned long
network_common_flat_address;
network_common_flat_address =
L4Application::GetNetworkCommonFlatAddress();
if (networkEggNotationFile)
{
Unregister_Object(networkEggNotationFile);
delete networkEggNotationFile;
networkEggNotationFile = NULL;
}
//
// If there is no net common, all we do is deregister the local host
//
if (network_common_flat_address == 0)
{
base_host = application->GetHostManager()->OrphanLocalHost();
my_l4host = Cast_Object(L4Host*, base_host);
Check(my_l4host);
Unregister_Object(my_l4host);
delete my_l4host;
return True;
}
Fail("L4NetworkManager::Shutdown -- netnub path not yet reconstructed");
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Send Sends a message to a single host.
//
void
L4NetworkManager::Send(Message *message, ClientID, HostID host_ID)
{
Host *base_host;
L4Host *l4host;
Check_Pointer(message);
Check(application);
Check(application->GetHostManager());
base_host = application->GetHostManager()->GetRemoteHost(host_ID);
if (base_host == NULL)
{
return;
}
l4host = Cast_Object(L4Host*, base_host);
if (l4host->GetConnectStatus() != L4Host::OnLineConnectionStatus)
{
return;
}
Fail("L4NetworkManager::Send -- netnub path not yet reconstructed");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::ExclusiveBroadcast Sends a message to every online host
// except the named client.
//
void
L4NetworkManager::ExclusiveBroadcast(Message *message, ClientID)
{
Check_Pointer(message);
Check(application);
//
// With no hosts online there is no one to broadcast to
//
if (numberOfMungaHostsConnected == 0 && numberOfConsoleHostsConnected == 0)
{
return;
}
Fail("L4NetworkManager::ExclusiveBroadcast -- netnub path not yet reconstructed");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::CheckBuffers Checks to see if there is a message for us
// buffered up in the network interface card.
//
Logical
L4NetworkManager::CheckBuffers(NetworkPacket *)
{
//
// No netnub present? Nothing can have arrived.
//
if (Net_Common_Ptr == NULL)
{
return False;
}
Fail("L4NetworkManager::CheckBuffers -- netnub path not yet reconstructed");
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
L4NetworkManager::RemovePacket(NetworkPacket *)
{
//
// No netnub present? Just return
//
if (Net_Common_Ptr == NULL)
{
return;
}
Fail("L4NetworkManager::RemovePacket -- netnub path not yet reconstructed");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
L4NetworkManager::ExecuteBackground()
{
Check(this);
if (!messageBuffer.IsEmpty())
{
messageBuffer.AttemptToSend();
return True;
}
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Marker Sends a text marker down the netnub spool for
// mission review annotation.
//
void
L4NetworkManager::Marker(char *)
{
//
// No netnub present? Just return
//
if (Net_Common_Ptr == NULL)
{
return;
}
Fail("L4NetworkManager::Marker -- netnub path not yet reconstructed");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Mode Switches the netnub between reliable and unreliable
// delivery.
//
void
L4NetworkManager::Mode(NetworkMode)
{
//
// No netnub present? Just return
//
if (Net_Common_Ptr == NULL)
{
return;
}
Fail("L4NetworkManager::Mode -- netnub path not yet reconstructed");
}
//
//#############################################################################
// Message handlers
//#############################################################################
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::ReceiveEggFileMessageHandler
//
void
L4NetworkManager::ReceiveEggFileMessageHandler(
ReceiveEggFileMessage *EggMessage
)
{
#if defined(LAB_ONLY)
DEBUG_STREAM << "Received Egg message #" << EggMessage->sequenceNumber
<< endl;
#endif
//
// 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");
currentNetworkState = NormalState;
//
// 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;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::AcknowledgeEggFileMessageHandler
//
void
L4NetworkManager::AcknowledgeEggFileMessageHandler(
AcknowledgeEggFileMessage *
)
{
#if defined(LAB_ONLY)
DEBUG_STREAM << "\nReceived egg acknowledged message\n";
#endif
eggAcknowledged = True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::HostConnectedMessageHandler
//
void
L4NetworkManager::HostConnectedMessageHandler(
HostConnectedMessage *HostConnected
)
{
//
// Get a pointer to the L4 host
//
Check(application);
Check(application->GetHostManager());
Host *connected_host =
application->GetHostManager()->GetRemoteHost(HostConnected->hostID);
L4Host *l4connected_host = Cast_Object(L4Host*, connected_host);
Check(l4connected_host);
//
// Set the host connection status to on line and increment the
// counter of hosts online.
//
l4connected_host->SetConnectStatus(L4Host::OnLineConnectionStatus);
switch (l4connected_host->GetHostType())
{
case GameMachineHostType:
numberOfMungaHostsConnected++;
DEBUG_STREAM << "Connected to GameMachineHost at ";
break;
case CameraShipHostType:
numberOfMungaHostsConnected++;
DEBUG_STREAM << "Connected to CameraShipHost at ";
break;
case MissionReviewHostType:
numberOfMungaHostsConnected++;
DEBUG_STREAM << "Connected to MissionReviewHost at ";
break;
case ConsoleHostType:
numberOfConsoleHostsConnected++;
DEBUG_STREAM << "Connected to ConsoleHost at ";
break;
default:
Fail("L4NetworkManager::HostConnectedMessageHandler - unknown host type");
break;
}
DEBUG_STREAM << HostConnected->networkAddress << endl;
if (numberOfMungaHostsConnected >= remoteHostCount)
{
DEBUG_STREAM << "All connections completed!\n";
Marker("MUNGA MARKER--All connections completed!\n");
//
//--------------------------------------------------------------------
// All hosts are up; 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);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::HostDisconnectedMessageHandler
// This message is assumed only to be sent by the console just prior to it
// disconnecting. It clues us to locally close and destroy the console host
// so the game will start normally even if the console isn't around.
//
void
L4NetworkManager::HostDisconnectedMessageHandler(
HostDisconnectedMessage *HostDisconnected
)
{
//
// Get a pointer to the L4 host
//
Check(application->GetHostManager());
Host *connected_host =
application->GetHostManager()->GetRemoteHost(HostDisconnected->hostID);
L4Host *l4connected_host = Cast_Object(L4Host*, connected_host);
Check(l4connected_host);
//
// Set the host connection status to off line, then close the connection.
//
l4connected_host->SetConnectStatus(L4Host::NoNetworkConnectionStatus);
NetworkAddress temp_net_address = l4connected_host->GetNetworkAddress();
CloseConnection(HostDisconnected->streamPointer);
//
// See what type of host it was that disconnected
//
switch (l4connected_host->GetHostType())
{
case GameMachineHostType:
numberOfMungaHostsConnected--;
DEBUG_STREAM << "\nDisconnected from GameMachineHost at ";
break;
case CameraShipHostType:
numberOfMungaHostsConnected--;
DEBUG_STREAM << "\nDisconnected from CameraShipHost at ";
break;
case MissionReviewHostType:
numberOfMungaHostsConnected--;
DEBUG_STREAM << "\nDisconnected from MissionReviewHost at ";
break;
case ConsoleHostType:
//
// Knock down the number of consoles online, then destroy the
// console host and recreate it; this resets all the internal
// buffers and pointers so check_buffers won't go crazy
//
numberOfConsoleHostsConnected--;
DEBUG_STREAM << "\nDisconnected from ConsoleHost at ";
application->GetHostManager()->OrphanRemoteHost(l4connected_host);
Unregister_Object(l4connected_host);
delete l4connected_host;
CreateConsoleHost();
break;
default:
Fail("L4NetworkManager::HostDisconnectedMessageHandler - unknown host type");
break;
}
DEBUG_STREAM << temp_net_address << "\n";
}
//
//#############################################################################
// Netnub wire primitives -- not yet reconstructed
//#############################################################################
//
unsigned long
L4NetworkManager::CheckSocket(unsigned long)
{
Fail("L4NetworkManager::CheckSocket -- netnub path not yet reconstructed");
return 0;
}
unsigned long
L4NetworkManager::ResolveAddress(CString)
{
Fail("L4NetworkManager::ResolveAddress -- netnub path not yet reconstructed");
return 0;
}
unsigned long
L4NetworkManager::GetMyAddress()
{
Fail("L4NetworkManager::GetMyAddress -- netnub path not yet reconstructed");
return 0;
}
unsigned long
L4NetworkManager::OpenConnection(int, int, int, int)
{
Fail("L4NetworkManager::OpenConnection -- netnub path not yet reconstructed");
return 0;
}
void
L4NetworkManager::CloseConnection(unsigned long)
{
Fail("L4NetworkManager::CloseConnection -- netnub path not yet reconstructed");
}
Logical
L4NetworkManager::GetNextMungaPacket(
NetworkPacket *,
HostManager::RemoteHostIterator *
)
{
Fail("L4NetworkManager::GetNextMungaPacket -- netnub path not yet reconstructed");
return False;
}
Logical
L4NetworkManager::SendMessageToNetnub(Message *, ClientID, HostID)
{
Fail("L4NetworkManager::SendMessageToNetnub -- netnub path not yet reconstructed");
return False;
}
void
L4NetworkManager::SendBatchedMessageToNetnub(
Message *,
ClientID,
DroppedMessageHostSocket *
)
{
Fail("L4NetworkManager::SendBatchedMessageToNetnub -- netnub path not yet reconstructed");
}
//
//#############################################################################
// L4NetworkManager__MessageBuffer
//#############################################################################
//
L4NetworkManager__MessageBuffer::L4NetworkManager__MessageBuffer(
L4NetworkManager *network_manager
):
messageQueueSocket(NULL, 1)
{
networkManager = network_manager;
currentQueueIndex = 0;
bufferSize = 0;
}
L4NetworkManager__MessageBuffer::~L4NetworkManager__MessageBuffer()
{
}
void
L4NetworkManager__MessageBuffer::AddSendRequest(
HostID,
NetworkClient::ClientID,
Receiver::Message *
)
{
Fail("L4NetworkManager__MessageBuffer::AddSendRequest -- netnub path not yet reconstructed");
}
void
L4NetworkManager__MessageBuffer::AttemptToSend()
{
Fail("L4NetworkManager__MessageBuffer::AttemptToSend -- netnub path not yet reconstructed");
}