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

172 lines
5.6 KiB
C++

/*
Rose Online Server Emulator
Copyright (C) 2006,2007 OSRose Team http://www.osrose.net
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
depeloped with Main erose/hrose source server + some change from the original eich source
*/
#ifndef _ROSE_PLAYER_
#define _ROSE_PLAYER_
#include "character.h"
/// Forward Declarations
class CMonster; // Forward declare
class CPlayer: public CCharacter
{
public:
CPlayer( CClientSocket* );
~CPlayer( );
//
CClientSocket* client;
bool questdebug;// Send PM's with quest information
bool Saved;// already save this player?(used ondisconnect/returnchar)
bool isInvisibleMode;
// Fairy
bool Fairy;
UINT FairyListIndex;
// variables
USEDITEM* UsedItem;
INFO* CharInfo;
RIDE* Ride;
TRADE* Trade;
PARTY* Party;
SHOP* Shop;
SESSION* Session;
CLAN* Clan;
UNION_s* Union_s;
ATTRIBUTES* Attr;
CRespawnPoints GMRespawnPoints;
// Inventory/storage
// +1: slot indices throughout the codebase run 0..MAX_* inclusive
CItem storageitems[MAX_STORAGE + 1];
unsigned int nstorageitems;
CItem items[MAX_INVENTORY + 1];
// skills/quickbar
SKILLS cskills[MAX_SKILL];
UINT bskills[MAX_BASICSKILL];
UINT quickbar[MAX_QUICKBAR];
unsigned short askill[30];
unsigned char askilllvl[30];
unsigned short pskill[30];
unsigned char pskilllvl[30];
int p_skills;
// ExJam Quest Code - Info
DWORD ActiveQuest; //active quest #
int CheckQuest; // The currently checked quest.
strings TriggerName[10];
SQuestData quest; // Character's quest information
int NPCvar; // holds reference value for ObjVar global structure
int RefVar; // holds reference value for second part of ObjVar structure
// Time
clock_t lastRegenTime;
clock_t lastSaveTime;
clock_t lastGG;
// Visible Lists
vector<CPlayer*> VisiblePlayers; // Visible players
vector<CDrop*> VisibleDrops; // Visible drops
vector<unsigned int> VisibleMonsters; // Visible monsters
vector<CNPC*> VisibleNPCs; // Visible npcs
// Battle Events
void onCheckForMonsterQuests_event (CMonster* Monster); // Called if the character had first hit and monster was killed.
// Functions
bool CheckPlayerLevelUP( );
bool canUseSkill(CSkills* skill);
void SetStats( );
bool GetPlayerInfo( );
bool IsMonster( );
bool CleanPlayerVector( );
bool loaddata( );
void savedata( );
void quicksave( );
void saveinventory( );
void loadinventory( );
void savestorage( );
void SaveBackupStorage( int logstate );
void loadstorage( );
UINT GetNewStorageItemSlot( CItem thisitem );
UINT GetNewItemSlot( CItem thisitem );
bool ClearObject( unsigned int otherclientid );
void RestartPlayerVal( );
bool Regeneration( );
bool PlayerHeal( );
bool VisiblityList( );
bool ChangeDialog( unsigned int npc, unsigned int dialog, unsigned int eventid = 0 );
bool SpawnToPlayer( CPlayer* player, CPlayer* otherclient );
bool RespawnPlayer(CPlayer* thisclient);
bool UpdateValues( );
void ReduceABC( );
CParty* GetParty( );
CLAN* GetClan( );
unsigned int AddItem( CItem item );
unsigned int Getnstorageitems( CPlayer* thisclient );
void UpdateInventory(unsigned int slot1, unsigned int slot2=0xffff );
// ExJam Quest Code
void savequests( CPlayer* thisclient );
SQuest* GetActiveQuest( );
int GetQuestVar(short nVarType, short nVarNO);
void SetQuestVar(short nVarType, short nVarNO, short nValue);
int ExecuteQuestTrigger(dword hash);
//PY Quest stuff
void SetQuestFlag(dword flagid, bool value);
void GetQuestFlag(dword falgid);
// Player Stats
unsigned int GetAttackPower( );
unsigned int GetDefense( );
unsigned int GetDodge( );
unsigned int GetXPRate( );
unsigned int GetItemDropRate( );
unsigned int GetItemDropCountRate( );
unsigned int GetZulyDropRate( );
unsigned int GetGreyDrops( );
unsigned int GetAccury( );
unsigned int GetMagicDefense( );
unsigned int GetMagicAttack( );
unsigned int GetCritical( );
unsigned int GetAttackSpeed( );
unsigned int GetMoveSpeed( );
unsigned int GetMaxHP( );
unsigned int GetMaxMP( );
float GetAttackDistance( );
unsigned int GetHPRegenAmount( );
unsigned int GetMPRegenAmount( );
unsigned int GetMaxWeight( );
unsigned int GetCurrentWeight( );
unsigned int GetMPReduction( );
unsigned int GetMaxSummonGauge( );
void GetExtraStats( );
unsigned int GetLevelEXP( );
unsigned int GetInt( );
// Skill
int GetNewSkillSlot(char skilltype);
void takeSkillCost( CSkills* skill );
};
#endif