Files
92thmsandClaude Sonnet 5 764fcb3b3f Port server to Linux and add Docker Compose deployment
Rebuilds (not Wine) the login/char/world servers natively for Linux via
CMake, and ships a single Docker image plus docker-compose stack (MariaDB +
3 servers) with all settings configurable via .env.

Linux portability:
- Src/Common/compat.h shims MSVC-only CRT calls (fopen_s, _strdup,
  strncpy_s, sprintf_s, SYSTEMTIME/GetLocalTime, WSAGetLastError, __cdecl)
  and adds a case-insensitive/backslash-tolerant path resolver for the
  Windows-authored STB/AIP data file paths.
- Fixed case-sensitive header includes and filenames (charserver.h vs
  CharServer.h, worldserver.h vs WorldServer.h, ../common vs ../Common).
- rose_inet_addr() resolves hostnames (not just literal IPs) for the
  server-to-server links, so docker-compose service names work.

Fixed three real bugs that only crashed on 64-bit Linux (silently tolerated
on 32-bit Windows):
- CIntStb::LoadSTB had an inverted fopen success/failure check, so STB game
  data (zones, items, etc.) was never actually loaded.
- GenerateCryptTables allocated its pointer table with sizeof(unsigned)
  instead of sizeof(unsigned*) -- a 1x vs 2x-size heap overflow on 64-bit.
- Crypto bit-twiddling relies throughout on signed-overflow-as-wraparound,
  which is UB in C++; GCC's -O3 exploited it and miscompiled
  GenerateCryptTables (Release-only crash). Fixed via -fwrapv.
Plus smaller fixes: off-by-one array bounds (inventory/storage/sell data),
SO_REUSEADDR on server sockets (containers restarting in the same netns hit
TIME_WAIT otherwise), and a va_list reused across multiple vprintf/vfprintf
calls in Log() that garbled every formatted log line on the Linux ABI.

Docker:
- CMakeLists.txt builds all three servers + shared Common code.
- Dockerfile: multi-stage build, one runtime image for all three servers,
  server role selected via `command: [login|char|world]`.
- docker-compose.yml: MariaDB (auto-imports database sql files/ on first
  run) + login/char/world (single channel), config rendered from
  docker/conf/*.conf.tmpl via envsubst at container start.
- .env.example documents every setting (ports, server names, rates,
  inter-server passwords, PUBLIC_HOST for internet-facing deployments).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 06:32:39 +00:00

168 lines
5.0 KiB
C++

// Props to ExJam for this code :D
#include "../WorldServer.h"
void CWorldServer::ReadAIP(strings path, dword index)
{
CRoseFile* fh = new CRoseFile(path, FM_READ | FM_BINARY);
if(fh->IsOpen())
{ // goto done;
//Log(MSG_LOAD, "Loading %s ", path);
dword BlockCount = fh->Get<dword>();
dword mintime = fh->Get<dword>();
dword mindamage = fh->Get<dword>();
dword titlestringlength = fh->Get<dword>();
strings title = new char[titlestringlength+1];
strings title2 = new char[32+1];
fh->Read(title, titlestringlength, 1);
for(dword i = 0; i < BlockCount; i++)
{
titlestringlength = 32;
fh->Read(title2, titlestringlength, 1);//on spawn-idle-attack-attacked-killed target-dead
dword RecordCount = fh->Get<dword>();
for(dword j = 0; j < RecordCount; j++)
{
CAip* script = new CAip();
fh->Read(title2, titlestringlength, 1);// 00 ==============================
script->ConditionCount = fh->Get<dword>();
if(script->ConditionCount > 0)
{
script->Conditions = new CAip::SAipDatum*[script->ConditionCount];
for(dword k = 0; k < script->ConditionCount; k++)
{
CAip::SAipDatum* data = new CAip::SAipDatum();
data->size = fh->Get<dword>();
data->opcode = fh->Get<dword>() - 0x04000001;
data->data = new byte[data->size - 8];
fh->Read(data->data, data->size - 8, 1);
script->Conditions[k] = data;
}
}
else
{
script->Conditions = NULL;
}
script->ActionCount = fh->Get<dword>();
if(script->ActionCount > 0)
{
script->Actions = new CAip::SAipDatum*[script->ActionCount];
for(dword k = 0; k < script->ActionCount; k++)
{
CAip::SAipDatum* data = new CAip::SAipDatum();
data->size = fh->Get<dword>();
data->opcode = fh->Get<dword>() - 0x0B000001;
data->data = new byte[data->size - 8];
fh->Read(data->data, data->size - 8, 1);
script->Actions[k] = data;
}
}
else
{
script->Actions = NULL;
}
script->AInumber = index;
script->AipID=((index*0x10000)+(i*0x100)+j);
script->minDamage = mindamage;
script->minTime = mintime;
script->recordcount[i] = RecordCount;
AipList.push_back( script );
}
}
}
else
Log( MSG_ERROR, "AIP File: '%s' failed to load properly", path );
fh->Close();
delete fh;
}
void CWorldServer::LoadAipData()
{
CStrStb* stbAip = new CStrStb("3DData/STB/FILE_AI.STB");
Log(MSG_INFO, "Loading AIP files");
for(dword i = 1; i < stbAip->Rows(); i++)
{
if(stbAip->Data(i, 0))
{
GServer->ReadAIP(stbAip->Data(i, 0),i);
}
}
//Log(MSG_INFO, "%i aip entrys",AipList.size());
Log(MSG_INFO, "Finished loading aip data ");
aiCondFunc[0] = &F_AI_COND_000;
aiCondFunc[1] = &F_AI_COND_001;
aiCondFunc[2] = &F_AI_COND_002;
aiCondFunc[3] = &F_AI_COND_003;
aiCondFunc[4] = &F_AI_COND_004;
aiCondFunc[5] = &F_AI_COND_005;
aiCondFunc[6] = &F_AI_COND_006;
aiCondFunc[7] = &F_AI_COND_007;
aiCondFunc[8] = &F_AI_COND_008;
aiCondFunc[9] = &F_AI_COND_009;
aiCondFunc[10] = &F_AI_COND_010;
aiCondFunc[11] = &F_AI_COND_011;
aiCondFunc[12] = &F_AI_COND_012;
aiCondFunc[13] = &F_AI_COND_013;
aiCondFunc[14] = &F_AI_COND_014;
aiCondFunc[15] = &F_AI_COND_015;
aiCondFunc[16] = &F_AI_COND_016;
aiCondFunc[17] = &F_AI_COND_017;
aiCondFunc[18] = &F_AI_COND_018;
aiCondFunc[19] = &F_AI_COND_019;
aiCondFunc[20] = &F_AI_COND_020;
aiCondFunc[21] = &F_AI_COND_021;
aiCondFunc[22] = &F_AI_COND_022;
aiCondFunc[23] = &F_AI_COND_023;
aiCondFunc[24] = &F_AI_COND_024;
aiCondFunc[25] = &F_AI_COND_025;
aiCondFunc[26] = &F_AI_COND_026;
aiCondFunc[27] = &F_AI_COND_027;
aiCondFunc[28] = &F_AI_COND_028;
aiCondFunc[29] = &F_AI_COND_029;
aiCondFunc[30] = &F_AI_COND_030;
aiActFunc[0] = &F_AI_ACT_000;
aiActFunc[1] = &F_AI_ACT_001;
aiActFunc[2] = &F_AI_ACT_002;
aiActFunc[3] = &F_AI_ACT_003;
aiActFunc[4] = &F_AI_ACT_004;
aiActFunc[5] = &F_AI_ACT_005;
aiActFunc[6] = &F_AI_ACT_006;
aiActFunc[7] = &F_AI_ACT_007;
aiActFunc[8] = &F_AI_ACT_008;
aiActFunc[9] = &F_AI_ACT_009;
aiActFunc[10] = &F_AI_ACT_010;
aiActFunc[11] = &F_AI_ACT_011;
aiActFunc[12] = &F_AI_ACT_012;
aiActFunc[13] = &F_AI_ACT_013;
aiActFunc[14] = &F_AI_ACT_014;
aiActFunc[15] = &F_AI_ACT_015;
aiActFunc[16] = &F_AI_ACT_016;
aiActFunc[17] = &F_AI_ACT_017;
aiActFunc[18] = &F_AI_ACT_018;
aiActFunc[19] = &F_AI_ACT_019;
aiActFunc[20] = &F_AI_ACT_020;
aiActFunc[21] = &F_AI_ACT_021;
aiActFunc[22] = &F_AI_ACT_022;
aiActFunc[23] = &F_AI_ACT_023;
aiActFunc[24] = &F_AI_ACT_024;
aiActFunc[25] = &F_AI_ACT_025;
aiActFunc[26] = &F_AI_ACT_026;
aiActFunc[27] = &F_AI_ACT_027;
aiActFunc[28] = &F_AI_ACT_028;
aiActFunc[29] = &F_AI_ACT_029;
aiActFunc[30] = &F_AI_ACT_030;
aiActFunc[31] = &F_AI_ACT_031;
aiActFunc[32] = &F_AI_ACT_032;
aiActFunc[33] = &F_AI_ACT_033;
aiActFunc[34] = &F_AI_ACT_034;
aiActFunc[35] = &F_AI_ACT_035;
aiActFunc[36] = &F_AI_ACT_036;
aiActFunc[37] = &F_AI_ACT_037;
delete stbAip;
}