The reconstructed tree now produces a runnable binary with the authentic 1995 toolchain (BC4.52 / tlink32 / DPMI32): - BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c) + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style; probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call) - L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals (standalone-benign ones no-op, network ones Fail loudly) + NetNub client globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path) - build410.sh: libs now built in the AUTHENTIC makefile member order (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing: tlink emits static-init records in module pull order, and alphabetical order booted into a null-vptr crash (IcomManager::ClassDerivations constructing before parent NetworkClient::ClassDerivations). Also fixed stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG) - BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine backfills (audio/gauge/resource/stream TUs) that closed the deep ledger Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in): BattleTech v4.10 BTL4Application::BTL4Application l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes), ApplicationManager and the BTL4Application ctor chain all execute real reconstructed code; boot halts at the first staged Fail() as designed. Next brick: the real l4net.cpp body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
441 lines
12 KiB
C++
441 lines
12 KiB
C++
# if !defined(MUNGA_HPP)
|
|
# include <munga.hpp>
|
|
# endif
|
|
#pragma hdrstop
|
|
|
|
# if !defined(HOSTMGR_HPP)
|
|
# include <hostmgr.hpp>
|
|
# endif
|
|
# if !defined(INTEREST_HPP)
|
|
# include <interest.hpp>
|
|
# endif
|
|
# if !defined(ICOM_HPP)
|
|
# include <icom.hpp>
|
|
# endif
|
|
# if !defined(APP_HPP)
|
|
# include <app.hpp>
|
|
# endif
|
|
# if !defined(NOTATION_HPP)
|
|
# include <notation.hpp>
|
|
# endif
|
|
# if !defined(NTTMGR_HPP)
|
|
# include <nttmgr.hpp>
|
|
# endif
|
|
|
|
#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::ClassDerivations,
|
|
NetworkClient::MessageHandlers
|
|
);
|
|
|
|
//
|
|
//#############################################################################
|
|
// Code for the network client class
|
|
//#############################################################################
|
|
//
|
|
Derivation
|
|
NetworkClient::ClassDerivations(Receiver::ClassDerivations, "NetworkClient");
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// 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(ClassDerivations);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// 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)
|
|
};
|
|
|
|
NetworkManager::MessageHandlerSet
|
|
NetworkManager::MessageHandlers(ELEMENTS(NetworkManager::MessageHandlerEntries), NetworkManager::MessageHandlerEntries, NetworkClient::MessageHandlers);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
NetworkManager::SharedData
|
|
NetworkManager::DefaultData(
|
|
NetworkManager::ClassDerivations,
|
|
NetworkManager::MessageHandlers
|
|
);
|
|
|
|
Derivation
|
|
NetworkManager::ClassDerivations(NetworkClient::ClassDerivations, "NetworkManager");
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Constructor for the NetworkManager
|
|
//
|
|
NetworkManager::NetworkManager(SharedData &shared_data):
|
|
NetworkClient(NetworkManagerClassID, shared_data, NetworkManagerClientID)
|
|
{
|
|
// basic init goes here
|
|
gameID = 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
|
|
//---------------------------------------------------------
|
|
//
|
|
Host *local_host = new Host(1, GameMachineHostType, 1);
|
|
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 << endl << 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 << endl << 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!");
|
|
}
|