Files
BT411/engine/MUNGA/MEMREG.cpp
T
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
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>
2026-07-05 21:03:40 -05:00

655 lines
12 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "plug.h"
#include "node.h"
#include "hash.h"
class MemoryRegister;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MRStats ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#define MR_FILENAME_LEN (64)
#define MR_HASH_SIZE (500)
class MRStats:
public Plug
{
friend class MemoryRegister;
public:
MRStats(
void *address,
MRStatsAddressType address_type,
char *fileName,
int lineNum
);
~MRStats();
private:
void
*address;
char
fileName[MR_FILENAME_LEN];
int
lineNum;
#ifdef MEMORY_VERIFY
MRStatsAddressType
addressType;
#endif
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryRegister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MemoryRegister:
public Node
{
public:
friend void Start_Registering_Function();
friend void Stop_Registering_Function();
friend void Register_Pointer_Function(
void *address,
MRStatsAddressType address_type,
char *file_name,
int line_num
);
friend void Unregister_Pointer_Function(
void *address,
char *file_name,
int line_num
);
friend void Address_Registration_Function(
void *address,
char *file_name,
int line_num
);
friend void Check_All_Signatures_Function(
char *file_name,
int line_num
);
MemoryRegister();
~MemoryRegister();
Logical
TestInstance() const;
void
Report();
private:
Logical
RegisterAddress(
void *address,
MRStatsAddressType,
char *fileName,
int lineNum
);
Logical
ReleaseAddress(
void *address,
char *fileName,
int lineNum
);
Logical
IsRegistered(
void *address
);
void
AddressRegistration(
void *address,
char *file_name,
int line_num
);
void
CheckAllSignatures(
char *file_name,
int line_num
);
static Logical
VerifyAddress(
void *address,
char *fileName,
int lineNum
);
private:
HashOf<MRStats*, unsigned long>
memoryStats;
Logical
collectStats;
long
registrations;
#ifdef MEMORY_VERIFY
Logical
checkAllSignatures;
ChainOf<MRStats*>
verificationSocket;
Time
nextTell;
#endif
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MemoryRegisterShell ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MemoryRegisterShell
{
public:
MemoryRegisterShell();
~MemoryRegisterShell();
static MemoryRegister
*store;
};
#ifdef MEMORY_REGISTER
MemoryRegisterShell
memory_register_shell;
#endif
MemoryRegister
*MemoryRegisterShell::store=NULL;
//
//###########################################################################
// MemoryRegisterShell
//###########################################################################
//
MemoryRegisterShell::MemoryRegisterShell()
{
store = new MemoryRegister;
Check(store);
}
//
//###########################################################################
// ~MemoryRegisterShell
//###########################################################################
//
MemoryRegisterShell::~MemoryRegisterShell()
{
MemoryRegister *obj;
Check(store);
store->Report();
obj = store;
store = NULL;
delete obj;
}
//
//###########################################################################
// MRStats
//###########################################################################
//
#ifdef MEMORY_VERIFY
MRStats::MRStats(
void *address,
MRStatsAddressType address_type,
char *fileName,
int lineNum
)
{
this->address = address;
this->lineNum = lineNum;
Str_Copy(this->fileName, fileName, MR_FILENAME_LEN);
this->addressType = address_type;
}
#else
MRStats::MRStats(
void *address,
MRStatsAddressType,
char *fileName,
int lineNum
)
{
this->address = address;
this->lineNum = lineNum;
Str_Copy(this->fileName, fileName, MR_FILENAME_LEN);
}
#endif
MRStats::~MRStats()
{
}
//
//###########################################################################
// MemoryRegister
//###########################################################################
//
#ifdef MEMORY_VERIFY
MemoryRegister::MemoryRegister():
memoryStats(MR_HASH_SIZE, NULL, True),
verificationSocket(NULL)
{
collectStats = True;
registrations = 0;
checkAllSignatures = True;
nextTell = Now();
}
#else
MemoryRegister::MemoryRegister():
memoryStats(MR_HASH_SIZE, NULL, True)
{
collectStats = True;
registrations = 0;
}
#endif
//
//###########################################################################
// ~MemoryRegister
//###########################################################################
//
MemoryRegister::~MemoryRegister()
{
}
//
//###########################################################################
// TestInstance
//###########################################################################
//
Logical
MemoryRegister::TestInstance() const
{
Node::TestInstance();
Check(&memoryStats);
#ifdef MEMORY_VERIFY
Check(&verificationSocket);
#endif
return True;
}
//
//###########################################################################
// RegisterAddress
//###########################################################################
//
Logical
MemoryRegister::RegisterAddress(
void *address,
MRStatsAddressType address_type,
char *fileName,
int lineNum
)
{
MRStats *stats;
if (!collectStats)
return True;
if (!VerifyAddress(address, fileName, lineNum))
return False;
Check(&memoryStats);
if ((stats = memoryStats.Find((unsigned long)address)) != NULL)
{
Tell(
stats->address << " : " <<
stats->fileName << '(' <<
stats->lineNum << ")\n"
);
Verify_Failed(
"MemoryRegister::RegisterAddress: Address already registered by above",
fileName,
lineNum
);
return False;
}
stats = new MRStats(address, address_type, fileName, lineNum);
Check(stats);
Check(&memoryStats);
collectStats = False;
memoryStats.AddValue(stats, (unsigned long)address);
#ifdef MEMORY_VERIFY
// Currently, only verify signatured objects
if (address_type == ObjectMRStatsAddressType)
{
Check(&verificationSocket);
checkAllSignatures = False;
verificationSocket.Add(stats);
checkAllSignatures = True;
}
#endif
collectStats = True;
registrations++;
return True;
}
//
//###########################################################################
// ReleaseAddress
//###########################################################################
//
Logical
MemoryRegister::ReleaseAddress(
void *address,
char *fileName,
int lineNum
)
{
MRStats *stats;
if (!collectStats)
return True;
if (!VerifyAddress(address, fileName, lineNum))
return False;
stats = memoryStats.Find((unsigned long)address);
if (stats != NULL)
{
Check(stats);
collectStats = False;
delete stats;
collectStats = True;
return True;
}
Verify_Failed(
"MemoryRegister::ReleaseAddress: Address not found",
fileName,
lineNum
);
return False;
}
//
//###########################################################################
// IsRegistered
//###########################################################################
//
Logical
MemoryRegister::IsRegistered(void *address)
{
return (memoryStats.Find((unsigned long)address) != NULL);
}
//
//###########################################################################
// AddressRegistration
//###########################################################################
//
void
MemoryRegister::AddressRegistration(
void *address,
char *file_name,
int line_num
)
{
MRStats *stats;
if ((stats = memoryStats.Find((unsigned long)address)) != NULL)
{
std::cout <<
stats->address << " : allocated at : " <<
stats->fileName << '(' <<
stats->lineNum << ")\n"
;
}
else
{
Verify_Failed(
"MemoryRegister::AddressRegistration: Address not found",
file_name,
line_num
);
}
}
//
//###########################################################################
// CheckAllSignatures
//###########################################################################
//
#ifdef MEMORY_VERIFY
void
MemoryRegister::CheckAllSignatures(
char *file_name,
int line_num
)
{
if (checkAllSignatures)
{
checkAllSignatures = False;
if (nextTell < Now())
{
nextTell += 1.0f;
Tell(".");
}
ChainIteratorOf<MRStats*>
iterator(&verificationSocket);
MRStats
*stats;
Check(&iterator);
while ((stats = iterator.ReadAndNext()) != NULL)
{
Check(stats);
switch (stats->addressType)
{
case PointerMRStatsAddressType:
Check_Pointer(stats->address);
break;
case ObjectMRStatsAddressType:
if (Is_Signature_Bad((Signature*)stats->address))
{
Tell(
stats->address << " : allocated at : " <<
stats->fileName << '(' <<
stats->lineNum << ") corrupted at : " <<
file_name << '(' <<
line_num << ")\n"
);
Check_Signature((Signature*)stats->address);
}
break;
default:
Fail("MemoryRegister::CheckAllSignatures - Unknown addressType");
break;
}
}
checkAllSignatures = True;
}
}
#else
void
MemoryRegister::CheckAllSignatures(
char*,
int
)
{
}
#endif
//
//###########################################################################
// Report
//###########################################################################
//
void
MemoryRegister::Report()
{
HashIteratorOf<MRStats*, unsigned long>
iterator(memoryStats);
MRStats
*stats;
Tell("MemoryRegister::Report\n");
Tell("Registrations " << registrations << std::endl);
Tell("Unreleased Addresses:\n");
while ((stats = iterator.ReadAndNext()) != NULL)
{
Check(stats);
std::cout <<
stats->address << " : " <<
stats->fileName << '(' <<
stats->lineNum << ")\n"
;
}
}
//
//###########################################################################
// VerifyAddress
//###########################################################################
//
Logical
MemoryRegister::VerifyAddress(
void *address,
char *fileName,
int lineNum
)
{
//
// HACK - An improvement would make sure that the memory
// address is within our heap or stack
//
if (address == 0L)
{
Verify_Failed(
"MemoryRegister::VerifyAddress: Address is NULL",
fileName,
lineNum
);
return False;
}
return True;
}
//
//###########################################################################
// Start
//###########################################################################
//
void
Start_Registering_Function()
{
#if 0
MemoryRegister::store = new MemoryRegister;
Check(MemoryRegister::store);
#endif
}
//
//###########################################################################
// Stop
//###########################################################################
//
void
Stop_Registering_Function()
{
#if 0
MemoryRegister *obj;
Check(MemoryRegister::store);
MemoryRegister::store->Report();
obj = MemoryRegister::store;
MemoryRegister::store = NULL;
delete obj;
#endif
}
//
//###########################################################################
// Register_Pointer_Function
//###########################################################################
//
void
Register_Pointer_Function(
void *address,
MRStatsAddressType address_type,
char *file_name,
int line_num
)
{
if (MemoryRegisterShell::store)
{
MemoryRegisterShell::store->RegisterAddress(
address,
address_type,
file_name,
line_num
);
}
}
//
//###########################################################################
// Unregister_Pointer_Function
//###########################################################################
//
void
Unregister_Pointer_Function(
void *address,
char *file_name,
int line_num
)
{
if (MemoryRegisterShell::store)
{
MemoryRegisterShell::store->ReleaseAddress(address, file_name, line_num);
}
}
//
//###########################################################################
// Address_Registration_Function
//###########################################################################
//
void
Address_Registration_Function(
void *address,
char *file_name,
int line_num
)
{
if (MemoryRegisterShell::store)
{
MemoryRegisterShell::store->AddressRegistration(address, file_name, line_num);
}
}
//
//###########################################################################
// Check_All_Signatures_Function
//###########################################################################
//
void
Check_All_Signatures_Function(
char *file_name,
int line_num
)
{
if (MemoryRegisterShell::store)
{
MemoryRegisterShell::store->CheckAllSignatures(file_name, line_num);
}
}