diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 96790858..a34d89cc 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -336,14 +336,14 @@ CPlayerData *CServer::GetPlayerData(int ClientID, int ColorID) return pData; else { - CPlayerData *pNewData = new CPlayerData(m_aClients[ClientID].m_aName, ColorID); + CPlayerData *pNewData = new CPlayerData(m_aClients[ClientID].m_aName, ColorID, Storage()); m_pPlayerData->Add(pNewData); return pNewData; } } else { - m_pPlayerData = new CPlayerData(m_aClients[ClientID].m_aName, ColorID); + m_pPlayerData = new CPlayerData(m_aClients[ClientID].m_aName, ColorID, Storage()); return m_pPlayerData; } diff --git a/src/engine/shared/linewriter.cpp b/src/engine/shared/linewriter.cpp new file mode 100644 index 00000000..8b1df272 --- /dev/null +++ b/src/engine/shared/linewriter.cpp @@ -0,0 +1,22 @@ +#include "linewriter.h" + +CLineWriter::CLineWriter(IOHANDLE IO) +{ + m_IO = IO; +} + +CLineWriter::~CLineWriter() +{ + Shutdown(); +} + +void CLineWriter::Shutdown() +{ + io_write_newline(m_IO); + io_close(m_IO); +} + +void CLineWriter::Write(const char *pStr) +{ + io_write(m_IO, pStr, str_length(pStr)); +} \ No newline at end of file diff --git a/src/engine/shared/linewriter.h b/src/engine/shared/linewriter.h new file mode 100644 index 00000000..9b9adbd8 --- /dev/null +++ b/src/engine/shared/linewriter.h @@ -0,0 +1,18 @@ +#ifndef ENGINE_SHARED_LINEWRITER_H +#define ENGINE_SHARED_LINEWRITER_H +#include + +class CLineWriter +{ + IOHANDLE m_IO; + +public: + CLineWriter(IOHANDLE IO); + ~CLineWriter(); + + void Shutdown(); + + void Write(const char *pStr); + void WriteNewLine() { io_write_newline(m_IO); } +}; +#endif diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index fd54c530..3cc56063 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -304,6 +304,8 @@ void CCharacter::SaveData() else pData->m_aWeaponType[i] = 0; } + + pData->SaveToFile(); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "Data save - color=%d", GetPlayer()->GetColorID()); @@ -1209,6 +1211,7 @@ void CCharacter::GiveStartWeapon() // load saved weapons CPlayerData *pData = GameServer()->Server()->GetPlayerData(GetPlayer()->GetCID(), GetPlayer()->GetColorID()); + pData->LoadDataFromFile(); bool GotItems = false; diff --git a/src/game/server/playerdata.cpp b/src/game/server/playerdata.cpp index ce43d28b..f0748486 100644 --- a/src/game/server/playerdata.cpp +++ b/src/game/server/playerdata.cpp @@ -1,9 +1,16 @@ #include #include +#include +#include +#include +#include + +#include + #include "playerdata.h" -CPlayerData::CPlayerData(const char *pName, int ColorID) +CPlayerData::CPlayerData(const char *pName, int ColorID, IStorage *pStorage) { m_pChild1 = 0; m_pChild2 = 0; @@ -11,6 +18,8 @@ CPlayerData::CPlayerData(const char *pName, int ColorID) str_copy(m_aName, pName, 16); m_ColorID = ColorID; + m_pStorage = pStorage; + LoadDataFromFile(); Reset(); } @@ -108,4 +117,96 @@ void CPlayerData::Reset() m_Gold = 0; m_HighestLevel = 0; m_HighestLevelSeed = 0; +} + +void CPlayerData::LoadDataFromFile() +{ + if (!g_Config.m_SvSavePlayerdata) + return; + + char aFilename[32]; + str_format(aFilename, sizeof(aFilename), "playerdatas/%s_%d.acc", m_aName, m_ColorID); + + IOHANDLE File = m_pStorage->OpenFile(aFilename, IOFLAG_READ, IStorage::TYPE_ALL); + if(!File) + { + SaveToFile(); // Create file + return; + } + CLineReader LineReader; + LineReader.Init(File); + + // read each line + while(char *pLine = LineReader.Get()) + { + // skip blank/empty lines as well as comments + if(str_length(pLine) > 0 && pLine[0] != '#' && pLine[0] != '\n' && pLine[0] != '\r' + && pLine[0] != '\t' && pLine[0] != '\v' && pLine[0] != ' ') + { + // TODO: Ugly, rewrite this + if(!str_comp_num(pLine, "Weapon: ", 8)) sscanf(pLine, "Weapon: %d %d %d %d %d %d %d %d %d %d %d %d", &(m_aWeaponType[0]), &(m_aWeaponType[1]), &(m_aWeaponType[2]), &(m_aWeaponType[3]), &(m_aWeaponType[4]), &(m_aWeaponType[5]), &(m_aWeaponType[6]), &(m_aWeaponType[7]), &(m_aWeaponType[8]), &(m_aWeaponType[9]), &(m_aWeaponType[10]), &(m_aWeaponType[11])); + if(!str_comp_num(pLine, "Ammo: ", 6)) sscanf(pLine, "Ammo: %d %d %d %d %d %d %d %d %d %d %d %d", &(m_aWeaponAmmo[0]), &(m_aWeaponAmmo[1]), &(m_aWeaponAmmo[2]), &(m_aWeaponAmmo[3]), &(m_aWeaponAmmo[4]), &(m_aWeaponAmmo[5]), &(m_aWeaponAmmo[6]), &(m_aWeaponAmmo[7]), &(m_aWeaponAmmo[8]), &(m_aWeaponAmmo[9]), &(m_aWeaponAmmo[10]), &(m_aWeaponAmmo[11])); + if(!str_comp_num(pLine, "Armor: ", 7)) sscanf(pLine, "Armor: %d", &m_Armor); + if(!str_comp_num(pLine, "Kits: ", 6)) sscanf(pLine, "Kits: %d", &m_Kits); + if(!str_comp_num(pLine, "Score: ", 7)) sscanf(pLine, "Score: %d", &m_Score); + if(!str_comp_num(pLine, "Gold: ", 6)) sscanf(pLine, "Gold: %d", &m_Gold); + if(!str_comp_num(pLine, "HighestLevelSeed: ", 18)) sscanf(pLine, "HighestLevelSeed: %d", &m_HighestLevelSeed); + else if(!str_comp_num(pLine, "HighestLevel: ", 14)) sscanf(pLine, "HighestLevel: %d", &m_HighestLevel); + } + } + + + io_close(File); +} + +void CPlayerData::SaveToFile() +{ + if (!g_Config.m_SvSavePlayerdata) + return; + + m_pStorage->CreateFolder("playerdatas", IStorage::TYPE_SAVE); + + char aFilename[32]; + str_format(aFilename, sizeof(aFilename), "playerdatas/%s_%d.acc", m_aName, m_ColorID); + + IOHANDLE File = m_pStorage->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); + if(!File) + return; + + CLineWriter Writer(File); + + char aBuf[256]; + +#define WRITE_LINE_INT(w, x) \ + do \ + { \ + str_format(aBuf, sizeof(aBuf), "%d", x); \ + (w).Write(aBuf); \ + } while(0) + + // Warning! Weapon Type change + Writer.Write("Weapon:"); + for (int i = 0; i < 12; i++) + { + Writer.Write(" "); + WRITE_LINE_INT(Writer, m_aWeaponType[i]); + } + Writer.Write("\nAmmo:"); + for (int i = 0; i < 12; i++) + { + Writer.Write(" "); + WRITE_LINE_INT(Writer, m_aWeaponAmmo[i]); + } + + Writer.Write("\nArmor: "); WRITE_LINE_INT(Writer, m_Armor); + + Writer.Write("\nKits: "); WRITE_LINE_INT(Writer, m_Kits); + + Writer.Write("\nScore: "); WRITE_LINE_INT(Writer, m_Score); + + Writer.Write("\nGold: "); WRITE_LINE_INT(Writer, m_Gold); + + Writer.Write("\nHighestLevel: "); WRITE_LINE_INT(Writer, m_HighestLevel); + + Writer.Write("\nHighestLevelSeed: "); WRITE_LINE_INT(Writer, m_HighestLevelSeed); } \ No newline at end of file diff --git a/src/game/server/playerdata.h b/src/game/server/playerdata.h index 1f51eefa..c0712584 100644 --- a/src/game/server/playerdata.h +++ b/src/game/server/playerdata.h @@ -8,8 +8,10 @@ class CPlayerData CPlayerData *m_pChild1; CPlayerData *m_pChild2; + IStorage *m_pStorage; + public: - CPlayerData(const char *pName, int ColorID); + CPlayerData(const char *pName, int ColorID, IStorage *pStorage); void Die(); void Reset(); @@ -35,6 +37,9 @@ class CPlayerData int GetHighScore(int Score); int GetPlayerCount(int Score); + + void LoadDataFromFile(); + void SaveToFile(); }; #endif diff --git a/src/game/variables.h b/src/game/variables.h index 55fc5a98..c28c4bac 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -150,6 +150,8 @@ MACRO_CONFIG_INT(SvBroadcastLock, sv_broadcastlock, 3, 0, 5, CFGFLAG_SERVER, "Br MACRO_CONFIG_INT(SvRandomMaps, sv_random_maps, 1, 0, 1, CFGFLAG_SERVER, "Random select map in maps list (1 = on, 0 = off)") +MACRO_CONFIG_INT(SvSavePlayerdata, sv_save_playerdata, 0, 0, 1, CFGFLAG_SERVER, "Save player data to a file") + // debug #ifdef CONF_DEBUG // this one can crash the server if not used correctly