Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
282 lines
5.4 KiB
C++
282 lines
5.4 KiB
C++
#pragma once
|
|
|
|
#include "receiver.h"
|
|
#include "time.h"
|
|
#include "hostid.h"
|
|
|
|
//WinSock support :ADB 01/06/07
|
|
#include <Winsock2.h>
|
|
#include <Ws2tcpip.h>
|
|
|
|
class Mission;
|
|
class NetworkManager;
|
|
class NotationFile;
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Support types for interest manager
|
|
//---------------------------------------------------
|
|
//
|
|
typedef Enumeration InterestZoneID;
|
|
const InterestZoneID NullInterestZoneID = 0;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkAddress ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
typedef LWord NetworkAddress;
|
|
|
|
extern const NetworkAddress NullNetworkAddress;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkClient ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
class NetworkPacket;
|
|
|
|
class NetworkClient:
|
|
public Receiver
|
|
{
|
|
friend class NetworkManager;
|
|
|
|
//##########################################################################
|
|
// Shared Data support
|
|
//
|
|
public:
|
|
static Derivation *GetClassDerivations();
|
|
static SharedData DefaultData;
|
|
|
|
//##########################################################################
|
|
// Construction and destruction support
|
|
//
|
|
public:
|
|
enum ClientID {
|
|
NetworkManagerClientID = 0,
|
|
EntityManagerClientID = 1,
|
|
HostManagerClientID = 2,
|
|
InterestManagerClientID = 3,
|
|
ApplicationClientID = 4,
|
|
ConsoleClientID = 5,
|
|
IcomManagerClientID = 6
|
|
};
|
|
|
|
private:
|
|
ClientID
|
|
clientID;
|
|
|
|
protected:
|
|
NetworkClient(
|
|
ClassID class_ID,
|
|
SharedData &virtual_data,
|
|
ClientID clientID
|
|
);
|
|
|
|
public:
|
|
~NetworkClient();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//##########################################################################
|
|
// Message packet receiving
|
|
//
|
|
public:
|
|
virtual void
|
|
ReceiveNetworkPacket(
|
|
NetworkPacket *packet,
|
|
Receiver::Message *packet_message
|
|
);
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Network ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
#define NETWORKMANAGER_BUFFER_SIZE 1600
|
|
|
|
class NetworkManager__ReceiveEggFileMessage;
|
|
|
|
class NetworkManager:
|
|
public NetworkClient
|
|
{
|
|
//##########################################################################
|
|
// Shared Data support
|
|
//
|
|
public:
|
|
static Derivation *GetClassDerivations();
|
|
static SharedData DefaultData;
|
|
|
|
public:
|
|
typedef Enumeration GameID;
|
|
|
|
//WinSock support :ADB 01/06/07
|
|
//const NetworkAddress&
|
|
// GetAddress()
|
|
NetworkAddress* GetAddress()
|
|
{return addresses;}
|
|
|
|
NetworkManager(SharedData &shared_data);
|
|
~NetworkManager();
|
|
|
|
void
|
|
SetGameID(GameID new_id)
|
|
{gameID = new_id;}
|
|
|
|
virtual void
|
|
Send(
|
|
Message *what,
|
|
ClientID to,
|
|
HostID host_id
|
|
);
|
|
void
|
|
Broadcast(
|
|
Message *what,
|
|
ClientID to
|
|
);
|
|
virtual void
|
|
ExclusiveBroadcast(
|
|
Message *what,
|
|
ClientID to
|
|
);
|
|
Logical
|
|
RoutePacket();
|
|
virtual Logical
|
|
ExecuteBackground();
|
|
|
|
NetworkClient*
|
|
GetNetworkClientPointer(ClientID client_id);
|
|
|
|
virtual void
|
|
StartConnecting(Mission *mission);
|
|
|
|
virtual Logical
|
|
Shutdown();
|
|
|
|
virtual void
|
|
Marker(char *) {};
|
|
|
|
enum NetworkMode
|
|
{
|
|
ReliableMode,
|
|
UnreliableMode
|
|
};
|
|
|
|
virtual void
|
|
Mode(NetworkMode) {};
|
|
|
|
// protected: //GY for test only
|
|
virtual Logical
|
|
CheckBuffers(NetworkPacket*);
|
|
virtual void
|
|
RemovePacket(NetworkPacket *packet);
|
|
|
|
GameID
|
|
gameID;
|
|
//WinSock support :ADB 01/06/07
|
|
//NetworkAddress address;
|
|
NetworkAddress* addresses;
|
|
int num_addresses;
|
|
//struct addrinfo* address;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Message Support
|
|
//
|
|
public:
|
|
//
|
|
// Message IDs
|
|
//
|
|
enum
|
|
{
|
|
ReceiveEggFileMessageID = NetworkClient::NextMessageID,
|
|
NextMessageID
|
|
};
|
|
|
|
//
|
|
// Message types
|
|
//
|
|
typedef NetworkManager__ReceiveEggFileMessage
|
|
ReceiveEggFileMessage;
|
|
|
|
//
|
|
// Message table
|
|
//
|
|
static const HandlerEntry
|
|
MessageHandlerEntries[];
|
|
//static MessageHandlerSet MessageHandlers;
|
|
static MessageHandlerSet& GetMessageHandlers();
|
|
|
|
void
|
|
ReceiveEggFileMessageHandler(ReceiveEggFileMessage* EggMessage);
|
|
|
|
protected:
|
|
char
|
|
*eggTempBuffer;
|
|
NotationFile
|
|
*networkEggNotationFile;
|
|
long
|
|
eggTempNext;
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkManager messages ~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// NetworkManager__ReceiveEggFileMessage
|
|
// NOTE: this message should be setup as variable length rather than fixing the
|
|
// size at 1000, I wasn't sure how to do this and there wasn't anyone around
|
|
// to ask at the time so I did it this way temporarily.
|
|
//
|
|
class NetworkManager__ReceiveEggFileMessage:
|
|
public Receiver__Message
|
|
{
|
|
public:
|
|
NetworkManager__ReceiveEggFileMessage(
|
|
int sequence_number,
|
|
int total_file_length,
|
|
char* notation_data,
|
|
int length
|
|
):
|
|
Receiver__Message(
|
|
NetworkManager::ReceiveEggFileMessageID,
|
|
sizeof(NetworkManager__ReceiveEggFileMessage)
|
|
),
|
|
sequenceNumber(sequence_number),
|
|
notationFileLength(total_file_length),
|
|
thisMessageLength(length)
|
|
{Mem_Copy(notationData,notation_data,length,sizeof(notationData));}
|
|
int
|
|
sequenceNumber;
|
|
int
|
|
notationFileLength;
|
|
int
|
|
thisMessageLength;
|
|
char
|
|
notationData[1000];
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~ NetworkPacketHeader ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
class NetworkPacketHeader
|
|
{
|
|
public:
|
|
NetworkClient::ClientID
|
|
clientID;
|
|
NetworkManager::GameID
|
|
gameID;
|
|
HostID
|
|
fromHost;
|
|
Time
|
|
timeStamp;
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkPacket ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
class NetworkPacket:
|
|
public NetworkPacketHeader
|
|
{
|
|
public:
|
|
Receiver::Message
|
|
messageData;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool operator==(SOCKADDR_IN &address1, SOCKADDR_IN &address2)
|
|
{
|
|
return (address1.sin_family == address2.sin_family &&
|
|
address1.sin_addr.S_un.S_addr == address2.sin_addr.S_un.S_addr &&
|
|
address1.sin_port == address2.sin_port);
|
|
}
|