mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Thread safe /save
This commit is contained in:
parent
f5ebbf59b6
commit
031ac52320
|
@ -186,7 +186,7 @@ void CSqlServer::CreateTables()
|
|||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_maps (Map VARCHAR(128) BINARY NOT NULL, Server VARCHAR(32) BINARY NOT NULL, Mapper VARCHAR(128) BINARY NOT NULL, Points INT DEFAULT 0, Stars INT DEFAULT 0, Timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY Map (Map)) CHARACTER SET utf8mb4;", m_aPrefix);
|
||||
executeSql(aBuf);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_saves (Savegame TEXT CHARACTER SET utf8mb4 BINARY NOT NULL, Map VARCHAR(128) BINARY NOT NULL, Code VARCHAR(128) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, Server CHAR(4), DDNet7 BOOL DEFAULT FALSE, UNIQUE KEY (Map, Code)) CHARACTER SET utf8mb4;", m_aPrefix);
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_saves (Savegame TEXT CHARACTER SET utf8mb4 BINARY NOT NULL, Map VARCHAR(128) BINARY NOT NULL, Code VARCHAR(128) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, Server CHAR(4), DDNet7 BOOL DEFAULT FALSE, SaveID VARCHAR(36), UNIQUE KEY (Map, Code)) CHARACTER SET utf8mb4;", m_aPrefix);
|
||||
executeSql(aBuf);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_points (Name VARCHAR(%d) BINARY NOT NULL, Points INT DEFAULT 0, UNIQUE KEY Name (Name)) CHARACTER SET utf8mb4;", m_aPrefix, MAX_NAME_LENGTH);
|
||||
|
|
|
@ -693,8 +693,6 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData)
|
|||
if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick())
|
||||
return;
|
||||
|
||||
int Team = ((CGameControllerDDRace*) pSelf->m_pController)->m_Teams.m_Core.Team(pResult->m_ClientID);
|
||||
|
||||
const char* pCode = pResult->GetString(0);
|
||||
char aCountry[5];
|
||||
if(str_length(pCode) > 3 && pCode[0] >= 'A' && pCode[0] <= 'Z' && pCode[1] >= 'A'
|
||||
|
@ -722,7 +720,7 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData)
|
|||
|
||||
if(str_in_list(g_Config.m_SvSqlValidServerNames, ",", aCountry))
|
||||
{
|
||||
pSelf->Score()->SaveTeam(Team, pCode, pResult->m_ClientID, aCountry);
|
||||
pSelf->Score()->SaveTeam(pResult->m_ClientID, pCode, aCountry);
|
||||
|
||||
if(g_Config.m_SvUseSQL)
|
||||
pPlayer->m_LastSQLQuery = pSelf->Server()->Tick();
|
||||
|
|
|
@ -1503,6 +1503,22 @@ void CCharacter::HandleTiles(int Index)
|
|||
// start
|
||||
if(((m_TileIndex == TILE_BEGIN) || (m_TileFIndex == TILE_BEGIN) || FTile1 == TILE_BEGIN || FTile2 == TILE_BEGIN || FTile3 == TILE_BEGIN || FTile4 == TILE_BEGIN || Tile1 == TILE_BEGIN || Tile2 == TILE_BEGIN || Tile3 == TILE_BEGIN || Tile4 == TILE_BEGIN) && (m_DDRaceState == DDRACE_NONE || m_DDRaceState == DDRACE_FINISHED || (m_DDRaceState == DDRACE_STARTED && !Team() && g_Config.m_SvTeam != 3)))
|
||||
{
|
||||
if(Teams()->GetSaving(Team()))
|
||||
{
|
||||
GameServer()->SendChatTarget(GetPlayer()->GetCID(), "Your team is currently getting saved"); // TODO: better message
|
||||
Die(GetPlayer()->GetCID(), WEAPON_WORLD);
|
||||
return;
|
||||
}
|
||||
if(g_Config.m_SvTeam == 2 && (Team() == TEAM_FLOCK || Teams()->Count(Team()) <= 1))
|
||||
{
|
||||
if(m_LastStartWarning < Server()->Tick() - 3 * Server()->TickSpeed())
|
||||
{
|
||||
GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You have to be in a team with other tees to start");
|
||||
m_LastStartWarning = Server()->Tick();
|
||||
}
|
||||
Die(GetPlayer()->GetCID(), WEAPON_WORLD);
|
||||
return;
|
||||
}
|
||||
if(g_Config.m_SvResetPickups)
|
||||
{
|
||||
for (int i = WEAPON_SHOTGUN; i < NUM_WEAPONS; ++i)
|
||||
|
@ -1512,16 +1528,6 @@ void CCharacter::HandleTiles(int Index)
|
|||
m_Core.m_ActiveWeapon = WEAPON_GUN;
|
||||
}
|
||||
}
|
||||
if(g_Config.m_SvTeam == 2 && (Team() == TEAM_FLOCK || Teams()->Count(Team()) <= 1))
|
||||
{
|
||||
if(m_LastStartWarning < Server()->Tick() - 3 * Server()->TickSpeed())
|
||||
{
|
||||
GameServer()->SendChatTarget(GetPlayer()->GetCID(),"You have to be in a team with other tees to start");
|
||||
m_LastStartWarning = Server()->Tick();
|
||||
}
|
||||
Die(GetPlayer()->GetCID(), WEAPON_WORLD);
|
||||
return;
|
||||
}
|
||||
|
||||
Teams()->OnCharacterStart(m_pPlayer->GetCID());
|
||||
m_CpActive = -2;
|
||||
|
|
|
@ -25,6 +25,9 @@ CGameControllerDDRace::~CGameControllerDDRace()
|
|||
void CGameControllerDDRace::Tick()
|
||||
{
|
||||
IGameController::Tick();
|
||||
#if defined(CONF_SQL)
|
||||
m_Teams.ProcessSaveTeam();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGameControllerDDRace::InitTeleporter()
|
||||
|
|
|
@ -45,7 +45,6 @@ void CPlayer::Reset()
|
|||
m_JoinTick = Server()->Tick();
|
||||
delete m_pCharacter;
|
||||
m_pCharacter = 0;
|
||||
m_KillMe = 0;
|
||||
m_SpectatorID = SPEC_FREEVIEW;
|
||||
m_LastActionTick = Server()->Tick();
|
||||
m_TeamChangeTick = Server()->Tick();
|
||||
|
@ -154,13 +153,6 @@ void CPlayer::Tick()
|
|||
if(!Server()->ClientIngame(m_ClientID))
|
||||
return;
|
||||
|
||||
if(m_KillMe != 0)
|
||||
{
|
||||
KillCharacter(m_KillMe);
|
||||
m_KillMe = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ChatScore > 0)
|
||||
m_ChatScore--;
|
||||
|
||||
|
@ -499,11 +491,6 @@ CCharacter *CPlayer::GetCharacter()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CPlayer::ThreadKillCharacter(int Weapon)
|
||||
{
|
||||
m_KillMe = Weapon;
|
||||
}
|
||||
|
||||
void CPlayer::KillCharacter(int Weapon)
|
||||
{
|
||||
if(m_pCharacter)
|
||||
|
@ -797,21 +784,30 @@ void CPlayer::ProcessSqlResult()
|
|||
if(m_SqlQueryResult == nullptr || m_SqlQueryResult.use_count() != 1)
|
||||
return;
|
||||
|
||||
if(m_SqlQueryResult->m_Done) // sql was query successful
|
||||
if(m_SqlQueryResult->m_Done) // SQL request was successful
|
||||
{
|
||||
for(int i = 0; i < (int)(sizeof(m_SqlQueryResult->m_aaMessages)/sizeof(m_SqlQueryResult->m_aaMessages[0])); i++)
|
||||
int NumMessages = (int)(sizeof(m_SqlQueryResult->m_aaMessages)/sizeof(m_SqlQueryResult->m_aaMessages[0]));
|
||||
switch(m_SqlQueryResult->m_MessageKind)
|
||||
{
|
||||
if(m_SqlQueryResult->m_aaMessages[i][0] == 0)
|
||||
break;
|
||||
switch(m_SqlQueryResult->m_MessageTarget)
|
||||
case CSqlPlayerResult::DIRECT:
|
||||
for(int i = 0; i < NumMessages; i++)
|
||||
{
|
||||
case CSqlPlayerResult::DIRECT:
|
||||
if(m_SqlQueryResult->m_aaMessages[i][0] == 0)
|
||||
break;
|
||||
GameServer()->SendChatTarget(m_ClientID, m_SqlQueryResult->m_aaMessages[i]);
|
||||
break;
|
||||
case CSqlPlayerResult::ALL:
|
||||
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, m_SqlQueryResult->m_aaMessages[i]);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CSqlPlayerResult::ALL:
|
||||
for(int i = 0; i < NumMessages; i++)
|
||||
{
|
||||
if(m_SqlQueryResult->m_aaMessages[i][0] == 0)
|
||||
break;
|
||||
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, m_SqlQueryResult->m_aaMessages[i]);
|
||||
}
|
||||
break;
|
||||
case CSqlPlayerResult::MAP_VOTE:
|
||||
// TODO: start vote
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_SqlQueryResult = nullptr;
|
||||
|
|
|
@ -47,7 +47,6 @@ public:
|
|||
void OnPredictedEarlyInput(CNetObj_PlayerInput *NewInput);
|
||||
void OnDisconnect(const char *pReason);
|
||||
|
||||
void ThreadKillCharacter(int Weapon = WEAPON_GAME);
|
||||
void KillCharacter(int Weapon = WEAPON_GAME);
|
||||
CCharacter *GetCharacter();
|
||||
|
||||
|
@ -174,7 +173,6 @@ public:
|
|||
bool m_SpecTeam;
|
||||
bool m_NinjaJetpack;
|
||||
bool m_Afk;
|
||||
int m_KillMe;
|
||||
bool m_HasFinishScore;
|
||||
|
||||
int m_ChatScore;
|
||||
|
|
|
@ -52,7 +52,9 @@ void CSaveTee::save(CCharacter *pChr)
|
|||
m_TuneZoneOld = pChr->m_TuneZoneOld;
|
||||
|
||||
if(pChr->m_StartTime)
|
||||
m_Time = pChr->Server()->Tick() - pChr->m_StartTime + 60 * pChr->Server()->TickSpeed();
|
||||
m_Time = pChr->Server()->Tick() - pChr->m_StartTime;
|
||||
else
|
||||
m_Time = 0;
|
||||
|
||||
m_Pos = pChr->m_Pos;
|
||||
m_PrevPos = pChr->m_PrevPos;
|
||||
|
@ -183,6 +185,9 @@ void CSaveTee::load(CCharacter *pChr, int Team)
|
|||
|
||||
char* CSaveTee::GetString()
|
||||
{
|
||||
// Add time penalty of 60 seconds (only to the database)
|
||||
int Time = m_Time + 60 * SERVER_TICK_SPEED;
|
||||
|
||||
str_format(m_aString, sizeof(m_aString),
|
||||
"%s\t%d\t%d\t%d\t%d\t%d\t"
|
||||
// weapons
|
||||
|
@ -223,7 +228,7 @@ char* CSaveTee::GetString()
|
|||
m_LastWeapon, m_QueuedWeapon,
|
||||
// tee states
|
||||
m_SuperJump, m_Jetpack, m_NinjaJetpack, m_FreezeTime, m_FreezeTick, m_DeepFreeze, m_EndlessHook,
|
||||
m_DDRaceState, m_Hit, m_Collision, m_TuneZone, m_TuneZoneOld, m_Hook, m_Time,
|
||||
m_DDRaceState, m_Hit, m_Collision, m_TuneZone, m_TuneZoneOld, m_Hook, Time,
|
||||
(int)m_Pos.x, (int)m_Pos.y, (int)m_PrevPos.x, (int)m_PrevPos.y,
|
||||
m_TeleCheckpoint, m_LastPenalty,
|
||||
(int)m_CorePos.x, (int)m_CorePos.y, m_Vel.x, m_Vel.y,
|
||||
|
@ -420,6 +425,38 @@ bool CSaveTeam::HandleSaveError(int Result, int ClientID, CGameContext *pGameCon
|
|||
return true;
|
||||
}
|
||||
|
||||
void CSaveTeam::HandleLoadError(int Result, int ClientID, const CSaveTeam &SavedTeam, CGameContext *pGameContext)
|
||||
{
|
||||
if(Result == 1)
|
||||
{
|
||||
pGameContext->SendChatTarget(ClientID, "You have to be in a team (from 1-63)");
|
||||
}
|
||||
else if(Result == 2)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Too many players in this team, should be %d", SavedTeam.GetMembersCount());
|
||||
pGameContext->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
else if(Result >= 10 && Result < 100)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Unable to find player: '%s'", SavedTeam.m_pSavedTees[Result-10].GetName());
|
||||
pGameContext->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
else if(Result >= 100 && Result < 200)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "%s is racing right now, Team can't be loaded if a Tee is racing already", SavedTeam.m_pSavedTees[Result-100].GetName());
|
||||
pGameContext->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
else if(Result >= 200)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Everyone has to be in a team, %s is in team 0 or the wrong team", SavedTeam.m_pSavedTees[Result-200].GetName());
|
||||
pGameContext->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
}
|
||||
|
||||
int CSaveTeam::load(int Team)
|
||||
{
|
||||
if(Team <= 0 || Team >= MAX_CLIENTS)
|
||||
|
@ -474,7 +511,7 @@ int CSaveTeam::load(int Team)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CSaveTeam::MatchPlayer(char name[16])
|
||||
int CSaveTeam::MatchPlayer(const char name[16])
|
||||
{
|
||||
for (int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
|
@ -486,7 +523,7 @@ int CSaveTeam::MatchPlayer(char name[16])
|
|||
return -1;
|
||||
}
|
||||
|
||||
CCharacter* CSaveTeam::MatchCharacter(char name[16], int SaveID)
|
||||
CCharacter* CSaveTeam::MatchCharacter(const char name[16], int SaveID)
|
||||
{
|
||||
int ID = MatchPlayer(name);
|
||||
if(ID >= 0 && m_pController->GameServer()->m_apPlayers[ID])
|
||||
|
|
|
@ -14,8 +14,8 @@ public:
|
|||
void load(CCharacter* pchr, int Team);
|
||||
char* GetString();
|
||||
int LoadString(char* String);
|
||||
vec2 GetPos() { return m_Pos; }
|
||||
char* GetName() { return m_aName; }
|
||||
vec2 GetPos() const { return m_Pos; }
|
||||
const char* GetName() const { return m_aName; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
CSaveTeam(IGameController* Controller);
|
||||
~CSaveTeam();
|
||||
char* GetString();
|
||||
int GetMembersCount() { return m_MembersCount; }
|
||||
int GetMembersCount() const { return m_MembersCount; }
|
||||
int LoadString(const char* String);
|
||||
int save(int Team);
|
||||
int load(int Team);
|
||||
|
@ -103,9 +103,10 @@ public:
|
|||
|
||||
// returns true if an error occured
|
||||
static bool HandleSaveError(int Result, int ClientID, CGameContext *pGameContext);
|
||||
static void HandleLoadError(int Result, int ClientID, const CSaveTeam &SavedTeam, CGameContext *pGameContext);
|
||||
private:
|
||||
int MatchPlayer(char name[16]);
|
||||
CCharacter* MatchCharacter(char name[16], int SaveID);
|
||||
int MatchPlayer(const char name[16]);
|
||||
CCharacter* MatchCharacter(const char name[16], int SaveID);
|
||||
|
||||
IGameController* m_pController;
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
virtual void RandomMap(int ClientID, int Stars) = 0;
|
||||
virtual void RandomUnfinishedMap(int ClientID, int Stars) = 0;
|
||||
|
||||
virtual void SaveTeam(int Team, const char *pCode, int ClientID, const char *pServer) = 0;
|
||||
virtual void SaveTeam(int ClientID, const char *pCode, const char *pServer) = 0;
|
||||
virtual void LoadTeam(const char *pCode, int ClientID) = 0;
|
||||
virtual void GetSaves(int ClientID) = 0;
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ void CFileScore::RandomUnfinishedMap(int ClientID, int Stars)
|
|||
GameServer()->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
|
||||
void CFileScore::SaveTeam(int Team, const char* Code, int ClientID, const char* Server)
|
||||
void CFileScore::SaveTeam(int ClientID, const char* Code, const char* Server)
|
||||
{
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "Save-function not supported in file based servers");
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
virtual void ShowPoints(int ClientID, const char* pName);
|
||||
virtual void RandomMap(int ClientID, int Stars);
|
||||
virtual void RandomUnfinishedMap(int ClientID, int Stars);
|
||||
virtual void SaveTeam(int Team, const char* Code, int ClientID, const char* Server);
|
||||
virtual void SaveTeam(int ClientID, const char* Code, const char* Server);
|
||||
virtual void LoadTeam(const char* Code, int ClientID);
|
||||
virtual void GetSaves(int ClientID);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ std::atomic_int CSqlScore::ms_InstanceCount(0);
|
|||
|
||||
CSqlPlayerResult::CSqlPlayerResult() :
|
||||
m_Done(0),
|
||||
m_MessageTarget(DIRECT)
|
||||
m_MessageKind(DIRECT)
|
||||
{
|
||||
for(int i = 0; i < (int)(sizeof(m_aaMessages)/sizeof(m_aaMessages[0])); i++)
|
||||
m_aaMessages[i][0] = 0;
|
||||
|
@ -324,82 +324,58 @@ bool CSqlScore::LoadScoreThread(CSqlServer* pSqlServer, const CSqlData<CSqlResul
|
|||
|
||||
void CSqlScore::MapVote(int ClientID, const char* MapName)
|
||||
{
|
||||
/*
|
||||
*ppResult = std::make_shared<CMapVoteResult>();
|
||||
|
||||
CSqlMapVoteData *Tmp = new CSqlMapVoteData();
|
||||
Tmp->m_ClientID = ClientID;
|
||||
Tmp->m_RequestedMap = MapName;
|
||||
Tmp->m_pResult = *ppResult;
|
||||
str_copy(Tmp->m_aFuzzyMap, MapName, sizeof(Tmp->m_aFuzzyMap));
|
||||
sqlstr::ClearString(Tmp->m_aFuzzyMap, sizeof(Tmp->m_aFuzzyMap));
|
||||
sqlstr::FuzzyString(Tmp->m_aFuzzyMap, sizeof(Tmp->m_aFuzzyMap));
|
||||
|
||||
thread_init_and_detach(ExecSqlFunc, new CSqlExecData(MapVoteThread, Tmp), "map vote");
|
||||
*/
|
||||
ExecPlayerThread(MapVoteThread, "map vote", ClientID, MapName, 0);
|
||||
}
|
||||
|
||||
bool CSqlScore::MapVoteThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure)
|
||||
bool CSqlScore::MapVoteThread(CSqlServer* pSqlServer, const CSqlData<CSqlPlayerResult> *pGameData, bool HandleFailure)
|
||||
{
|
||||
/*
|
||||
const CSqlMapVoteData *pData = dynamic_cast<const CSqlMapVoteData *>(pGameData);
|
||||
const CSqlPlayerRequest *pData = dynamic_cast<const CSqlPlayerRequest *>(pGameData);
|
||||
auto paMessages = pData->m_pResult->m_aaMessages;
|
||||
|
||||
if (HandleFailure)
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
char aFuzzyMap[128];
|
||||
str_copy(aFuzzyMap, pData->m_Name.Str(), sizeof(aFuzzyMap));
|
||||
sqlstr::ClearString(aFuzzyMap, sizeof(aFuzzyMap));
|
||||
sqlstr::FuzzyString(aFuzzyMap, sizeof(aFuzzyMap));
|
||||
|
||||
char aBuf[768];
|
||||
str_format(aBuf, sizeof(aBuf), "SELECT Map, Server FROM %s_maps WHERE Map LIKE '%s' COLLATE utf8mb4_general_ci ORDER BY CASE WHEN Map = '%s' THEN 0 ELSE 1 END, CASE WHEN Map LIKE '%s%%' THEN 0 ELSE 1 END, LENGTH(Map), Map LIMIT 1;", pSqlServer->GetPrefix(), pData->m_aFuzzyMap, pData->m_RequestedMap.ClrStr(), pData->m_RequestedMap.ClrStr());
|
||||
str_format(aBuf, sizeof(aBuf),
|
||||
"SELECT Map, Server "
|
||||
"FROM %s_maps "
|
||||
"WHERE Map LIKE '%s' COLLATE utf8mb4_general_ci "
|
||||
"ORDER BY "
|
||||
"CASE WHEN Map = '%s' THEN 0 ELSE 1 END, "
|
||||
"CASE WHEN Map LIKE '%s%%' THEN 0 ELSE 1 END, "
|
||||
"LENGTH(Map), Map "
|
||||
"LIMIT 1;",
|
||||
pSqlServer->GetPrefix(), aFuzzyMap,
|
||||
pData->m_Name.ClrStr(), pData->m_Name.ClrStr()
|
||||
);
|
||||
pSqlServer->executeSqlQuery(aBuf);
|
||||
|
||||
CPlayer *pPlayer = pData->GameServer()->m_apPlayers[pData->m_ClientID];
|
||||
|
||||
int64 Now = pData->Server()->Tick();
|
||||
int Timeleft = 0;
|
||||
|
||||
if(!pPlayer)
|
||||
goto end;
|
||||
|
||||
Timeleft = pPlayer->m_LastVoteCall + pData->Server()->TickSpeed()*g_Config.m_SvVoteDelay - Now;
|
||||
|
||||
if(pSqlServer->GetResults()->rowsCount() != 1)
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "No map like \"%s\" found. Try adding a '%%' at the start if you don't know the first character. Example: /map %%castle for \"Out of Castle\"", pData->m_RequestedMap.Str());
|
||||
pData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
|
||||
}
|
||||
else if(Now < pPlayer->m_FirstVoteTick)
|
||||
{
|
||||
char aBuf[64];
|
||||
str_format(aBuf, sizeof(aBuf), "You must wait %d seconds before making your first vote", (int)((pPlayer->m_FirstVoteTick - Now) / pData->Server()->TickSpeed()) + 1);
|
||||
pData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
|
||||
}
|
||||
else if(pPlayer->m_LastVoteCall && Timeleft > 0)
|
||||
{
|
||||
char aChatmsg[512] = {0};
|
||||
str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (Timeleft/pData->Server()->TickSpeed())+1);
|
||||
pData->GameServer()->SendChatTarget(pData->m_ClientID, aChatmsg);
|
||||
}
|
||||
else if(time_get() < pData->GameServer()->m_LastMapVote + (time_freq() * g_Config.m_SvVoteMapTimeDelay))
|
||||
{
|
||||
char chatmsg[512] = {0};
|
||||
str_format(chatmsg, sizeof(chatmsg), "There's a %d second delay between map-votes, please wait %d seconds.", g_Config.m_SvVoteMapTimeDelay, (int)(((pData->GameServer()->m_LastMapVote+(g_Config.m_SvVoteMapTimeDelay * time_freq()))/time_freq())-(time_get()/time_freq())));
|
||||
pData->GameServer()->SendChatTarget(pData->m_ClientID, chatmsg);
|
||||
str_format(paMessages[0], sizeof(paMessages[0]),
|
||||
"No map like \"%s\" found. "
|
||||
"Try adding a '%%' at the start if you don't know the first character. "
|
||||
"Example: /map %%castle for \"Out of Castle\"",
|
||||
pData->m_Name.Str());
|
||||
}
|
||||
else
|
||||
{
|
||||
pSqlServer->GetResults()->next();
|
||||
str_copy(pData->m_pResult->m_aMap, pSqlServer->GetResults()->getString("Map").c_str(), sizeof(pData->m_pResult->m_aMap));
|
||||
str_copy(pData->m_pResult->m_aServer, pSqlServer->GetResults()->getString("Server").c_str(), sizeof(pData->m_pResult->m_aServer));
|
||||
auto Server = pSqlServer->GetResults()->getString("Server");
|
||||
auto Map = pSqlServer->GetResults()->getString("Map");
|
||||
strcpy(paMessages[0], "/map"); // reason
|
||||
str_copy(paMessages[1], Server.c_str(), sizeof(paMessages[0]));
|
||||
str_copy(paMessages[2], Map.c_str(), sizeof(paMessages[0]));
|
||||
|
||||
for(char *p = pData->m_pResult->m_aServer; *p; p++)
|
||||
for(char *p = paMessages[1]; *p; p++) // lower case server
|
||||
*p = tolower(*p);
|
||||
|
||||
pData->m_pResult->m_ClientID = pData->m_ClientID;
|
||||
|
||||
pData->m_pResult->m_Done = true;
|
||||
}
|
||||
end:
|
||||
pData->m_pResult->m_Done = true;
|
||||
return true;
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
|
@ -407,13 +383,6 @@ bool CSqlScore::MapVoteThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult>
|
|||
dbg_msg("sql", "MySQL Error: %s", e.what());
|
||||
dbg_msg("sql", "ERROR: Could not start Mapvote");
|
||||
}
|
||||
catch (CGameContextError &e)
|
||||
{
|
||||
dbg_msg("sql", "WARNING: Aborted mapvote due to reload/change of map.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -865,7 +834,7 @@ bool CSqlScore::ShowRankThread(CSqlServer* pSqlServer, const CSqlData<CSqlPlayer
|
|||
}
|
||||
else
|
||||
{
|
||||
pData->m_pResult->m_MessageTarget = CSqlPlayerResult::ALL;
|
||||
pData->m_pResult->m_MessageKind = CSqlPlayerResult::ALL;
|
||||
str_format(pData->m_pResult->m_aaMessages[0], sizeof(pData->m_pResult->m_aaMessages[0]),
|
||||
"%d. %s Time: %02d:%05.2f, requested by %s",
|
||||
Rank, pSqlServer->GetResults()->getString("Name").c_str(),
|
||||
|
@ -965,7 +934,7 @@ bool CSqlScore::ShowTeamRankThread(CSqlServer* pSqlServer, const CSqlData<CSqlPl
|
|||
}
|
||||
else
|
||||
{
|
||||
pData->m_pResult->m_MessageTarget = CSqlPlayerResult::ALL;
|
||||
pData->m_pResult->m_MessageKind = CSqlPlayerResult::ALL;
|
||||
str_format(pData->m_pResult->m_aaMessages[0], sizeof(pData->m_pResult->m_aaMessages[0]),
|
||||
"%d. %s Team time: %02d:%05.02f, requested by %s",
|
||||
Rank, aNames, (int)(Time/60), Time-((int)Time/60*60), pData->m_RequestingPlayer.Str());
|
||||
|
@ -1102,7 +1071,6 @@ bool CSqlScore::ShowTeamTop5Thread(CSqlServer* pSqlServer, const CSqlData<CSqlPl
|
|||
int TeamSize = pSqlServer->GetResults()->getInt("TeamSize");
|
||||
float Time = (float)pSqlServer->GetResults()->getDouble("Time");
|
||||
int Rank = pSqlServer->GetResults()->getInt("Rank");
|
||||
printf("%d", TeamSize);
|
||||
|
||||
char aNames[2300] = { 0 };
|
||||
for(int i = 0; i < TeamSize; i++)
|
||||
|
@ -1280,7 +1248,7 @@ bool CSqlScore::ShowPointsThread(CSqlServer* pSqlServer, const CSqlData<CSqlPlay
|
|||
int Count = pSqlServer->GetResults()->getInt("Points");
|
||||
int Rank = pSqlServer->GetResults()->getInt("Rank");
|
||||
auto Name = pSqlServer->GetResults()->getString("Name");
|
||||
pData->m_pResult->m_MessageTarget = CSqlPlayerResult::ALL;
|
||||
pData->m_pResult->m_MessageKind = CSqlPlayerResult::ALL;
|
||||
str_format(paMessages[0], sizeof(paMessages[0]),
|
||||
"%d. %s Points: %d, requested by %s",
|
||||
Rank, Name.c_str(), Count, pData->m_RequestingPlayer.Str());
|
||||
|
@ -1499,126 +1467,128 @@ bool CSqlScore::RandomUnfinishedMapThread(CSqlServer* pSqlServer, const CSqlData
|
|||
return false;
|
||||
}
|
||||
|
||||
void CSqlScore::SaveTeam(int Team, const char* Code, int ClientID, const char* Server)
|
||||
void CSqlScore::SaveTeam(int ClientID, const char* Code, const char* Server)
|
||||
{
|
||||
/*
|
||||
if(((CGameControllerDDRace*)(GameServer()->m_pController))->m_Teams.GetSaving(Team))
|
||||
auto pController = ((CGameControllerDDRace*)(GameServer()->m_pController));
|
||||
int Team = pController->m_Teams.m_Core.Team(ClientID);
|
||||
if(pController->m_Teams.GetSaving(Team))
|
||||
return;
|
||||
|
||||
CSaveTeam SavedTeam(GameServer()->m_pController);
|
||||
int Result = SavedTeam.save(Team);
|
||||
auto SaveResult = std::make_shared<CSqlSaveResult>(ClientID, pController);
|
||||
int Result = SaveResult->m_SavedTeam.save(Team);
|
||||
if(CSaveTeam::HandleSaveError(Result, ClientID, GameServer()))
|
||||
return;
|
||||
// disable joining team while saving
|
||||
((CGameControllerDDRace*)(GameServer()->m_pController))->m_Teams.SetSaving(Team, true);
|
||||
pController->m_Teams.SetSaving(Team, SaveResult);
|
||||
|
||||
CSqlTeamSave *Tmp = new CSqlTeamSave();
|
||||
Tmp->m_Team = Team;
|
||||
Tmp->m_ClientID = ClientID;
|
||||
// copy both save code and save state into the thread struct
|
||||
CSqlTeamSave *Tmp = new CSqlTeamSave(SaveResult);
|
||||
Tmp->m_Code = Code;
|
||||
Tmp->m_SaveState = SavedTeam.GetString();
|
||||
Tmp->m_Map = g_Config.m_SvMap;
|
||||
FormatUuid(RandomUuid(), Tmp->m_Uuid, UUID_MAXSTRSIZE);
|
||||
str_copy(Tmp->m_Server, Server, sizeof(Tmp->m_Server));
|
||||
str_copy(Tmp->m_ClientName, this->Server()->ClientName(Tmp->m_ClientID), sizeof(Tmp->m_ClientName));
|
||||
str_copy(Tmp->m_ClientName, this->Server()->ClientName(ClientID), sizeof(Tmp->m_ClientName));
|
||||
|
||||
// TODO: log event in Teehistorian
|
||||
// TODO: find a way to send all players in the team the save code
|
||||
((CGameControllerDDRace*)(GameServer()->m_pController))->m_Teams.KillSavedTeam(Team);
|
||||
thread_init_and_detach(ExecSqlFunc, new CSqlExecData(SaveTeamThread, Tmp, false), "save team");
|
||||
*/
|
||||
// TODO: log event in teehistorian
|
||||
pController->m_Teams.KillSavedTeam(ClientID, Team);
|
||||
char aBuf[512];
|
||||
// TODO: better message, maybe hint that one should wait until the next message to leave
|
||||
str_format(aBuf, sizeof(aBuf), "Saving team initiated by '%s'", this->Server()->ClientName(ClientID));
|
||||
GameServer()->SendChatTeam(Team, aBuf);
|
||||
thread_init_and_detach(
|
||||
CSqlExecData<CSqlSaveResult>::ExecSqlFunc,
|
||||
new CSqlExecData<CSqlSaveResult>(SaveTeamThread, Tmp, false),
|
||||
"save team");
|
||||
}
|
||||
|
||||
bool CSqlScore::SaveTeamThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure)
|
||||
bool CSqlScore::SaveTeamThread(CSqlServer* pSqlServer, const CSqlData<CSqlSaveResult> *pGameData, bool HandleFailure)
|
||||
{
|
||||
/*
|
||||
const CSqlTeamSave *pData = dynamic_cast<const CSqlTeamSave *>(pGameData);
|
||||
|
||||
try
|
||||
sqlstr::CSqlString<10> SaveState = pData->m_pResult->m_SavedTeam.GetString();
|
||||
if(HandleFailure)
|
||||
{
|
||||
if (HandleFailure)
|
||||
if (!g_Config.m_SvSqlFailureFile[0])
|
||||
return true;
|
||||
|
||||
lock_wait(ms_FailureFileLock);
|
||||
IOHANDLE File = io_open(g_Config.m_SvSqlFailureFile, IOFLAG_APPEND);
|
||||
if(File)
|
||||
{
|
||||
if (!g_Config.m_SvSqlFailureFile[0])
|
||||
return true;
|
||||
dbg_msg("sql", "ERROR: Could not save Teamsave, writing insert to a file now...");
|
||||
|
||||
lock_wait(ms_FailureFileLock);
|
||||
IOHANDLE File = io_open(g_Config.m_SvSqlFailureFile, IOFLAG_APPEND);
|
||||
if(File)
|
||||
{
|
||||
dbg_msg("sql", "ERROR: Could not save Teamsave, writing insert to a file now...");
|
||||
|
||||
char aBuf[65536];
|
||||
str_format(aBuf, sizeof(aBuf),
|
||||
"INSERT IGNORE INTO %%s_saves(Savegame, Map, Code, Timestamp, Server, DDNet7) "
|
||||
"VALUES ('%s', '%s', '%s', CURRENT_TIMESTAMP(), '%s', false);",
|
||||
pData->m_SaveState, pData->m_Map.ClrStr(), pData->m_Code.ClrStr(), pData->m_Server
|
||||
);
|
||||
io_write(File, aBuf, str_length(aBuf));
|
||||
io_write_newline(File);
|
||||
io_close(File);
|
||||
lock_unlock(ms_FailureFileLock);
|
||||
|
||||
pData->GameServer()->SendBroadcast("Database connection failed, teamsave written to a file instead. Admins will add it manually in a few days.", -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
char aBuf[65536];
|
||||
str_format(aBuf, sizeof(aBuf),
|
||||
"INSERT IGNORE INTO %%s_saves(Savegame, Map, Code, Timestamp, Server, SaveID, DDNet7) "
|
||||
"VALUES ('%s', '%s', '%s', CURRENT_TIMESTAMP(), '%s', '%s', false)",
|
||||
SaveState.ClrStr(), pData->m_Map.ClrStr(),
|
||||
pData->m_Code.ClrStr(), pData->m_Server, pData->m_Uuid
|
||||
);
|
||||
io_write(File, aBuf, str_length(aBuf));
|
||||
io_write_newline(File);
|
||||
io_close(File);
|
||||
lock_unlock(ms_FailureFileLock);
|
||||
dbg_msg("sql", "ERROR: Could not save Teamsave, NOT even to a file");
|
||||
return false;
|
||||
}
|
||||
|
||||
pData->m_pResult->m_Status = CSqlSaveResult::SAVE_SUCCESS;
|
||||
strcpy(pData->m_pResult->m_aBroadcast,
|
||||
"Database connection failed, teamsave written to a file instead. Admins will add it manually in a few days.");
|
||||
|
||||
return true;
|
||||
}
|
||||
lock_unlock(ms_FailureFileLock);
|
||||
dbg_msg("sql", "ERROR: Could not save Teamsave, NOT even to a file");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "lock tables %s_saves write;", pSqlServer->GetPrefix());
|
||||
pSqlServer->executeSql(aBuf);
|
||||
str_format(aBuf, sizeof(aBuf), "select Savegame from %s_saves where Code = '%s' and Map = '%s';", pSqlServer->GetPrefix(), pData->m_Code.ClrStr(), pData->m_Map.ClrStr());
|
||||
str_format(aBuf, sizeof(aBuf),
|
||||
"SELECT Savegame "
|
||||
"FROM %s_saves "
|
||||
"WHERE Code = '%s' AND Map = '%s';",
|
||||
pSqlServer->GetPrefix(), pData->m_Code.ClrStr(), pData->m_Map.ClrStr());
|
||||
pSqlServer->executeSqlQuery(aBuf);
|
||||
|
||||
if (pSqlServer->GetResults()->rowsCount() == 0)
|
||||
{
|
||||
char aBuf[65536];
|
||||
str_format(aBuf, sizeof(aBuf),
|
||||
"INSERT IGNORE INTO %s_saves(Savegame, Map, Code, Timestamp, Server, DDNet7) VALUES ('%s', '%s', '%s', CURRENT_TIMESTAMP(), '%s', false)",
|
||||
pSqlServer->GetPrefix(), pData->m_SaveState.ClrStr(), pData->m_Map.ClrStr(), pData->m_Code.ClrStr(), pData->m_Server
|
||||
"INSERT IGNORE INTO %s_saves(Savegame, Map, Code, Timestamp, Server, SaveID, DDNet7) "
|
||||
"VALUES ('%s', '%s', '%s', CURRENT_TIMESTAMP(), '%s', '%s', false)",
|
||||
pSqlServer->GetPrefix(), SaveState.ClrStr(), pData->m_Map.ClrStr(),
|
||||
pData->m_Code.ClrStr(), pData->m_Server, pData->m_Uuid
|
||||
);
|
||||
dbg_msg("sql", "%s", aBuf);
|
||||
pSqlServer->executeSql(aBuf);
|
||||
|
||||
// be sure to keep all calls to pData->GameServer() after inserting the save, otherwise it might be lost due to CGameContextError.
|
||||
|
||||
char aBuf2[512];
|
||||
str_format(aBuf2, sizeof(aBuf2), "Team successfully saved by %s. Use '/load %s' to continue", pData->m_ClientName, pData->m_Code.Str());
|
||||
pData->GameServer()->SendChatTeam(Team, aBuf2);
|
||||
str_format(pData->m_pResult->m_aMessage, sizeof(pData->m_pResult->m_aMessage),
|
||||
"Team successfully saved by %s. Use '/load %s' to continue",
|
||||
pData->m_ClientName, pData->m_Code.Str());
|
||||
pData->m_pResult->m_Status = CSqlSaveResult::SAVE_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("sql", "ERROR: This save-code already exists");
|
||||
pData->GameServer()->SendChatTarget(pData->m_ClientID, "This save-code already exists");
|
||||
pData->m_pResult->m_Status = CSqlSaveResult::SAVE_FAILED;
|
||||
strcpy(pData->m_pResult->m_aMessage, "This save-code already exists");
|
||||
}
|
||||
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
{
|
||||
pData->m_pResult->m_Status = CSqlSaveResult::SAVE_FAILED;
|
||||
dbg_msg("sql", "MySQL Error: %s", e.what());
|
||||
dbg_msg("sql", "ERROR: Could not save the team");
|
||||
pData->GameServer()->SendChatTarget(pData->m_ClientID, "MySQL Error: Could not save the team");
|
||||
|
||||
strcpy(pData->m_pResult->m_aMessage, "MySQL Error: Could not save the team");
|
||||
pSqlServer->executeSql("unlock tables;");
|
||||
return false;
|
||||
}
|
||||
catch (CGameContextError &e)
|
||||
{
|
||||
dbg_msg("sql", "WARNING: Could not send chatmessage during saving team due to reload/change of map.");
|
||||
}
|
||||
}
|
||||
catch (CGameContextError &e)
|
||||
{
|
||||
dbg_msg("sql", "WARNING: Aborted saving team due to reload/change of map.");
|
||||
}
|
||||
|
||||
pSqlServer->executeSql("unlock tables;");
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSqlScore::LoadTeam(const char* Code, int ClientID)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#define GAME_SERVER_SCORE_SQL_H
|
||||
|
||||
#include <engine/server/sql_string_helpers.h>
|
||||
#include <engine/shared/uuid_manager.h>
|
||||
|
||||
#include "../score.h"
|
||||
|
||||
|
@ -20,10 +19,40 @@ public:
|
|||
{
|
||||
DIRECT,
|
||||
ALL,
|
||||
} m_MessageTarget;
|
||||
MAP_VOTE, // 3 Messages: Reason, Server, Map
|
||||
} m_MessageKind;
|
||||
char m_aaMessages[7][512];
|
||||
};
|
||||
|
||||
class CSqlSaveResult {
|
||||
public:
|
||||
CSqlSaveResult(int PlayerID, IGameController* Controller) :
|
||||
m_Status(SAVE_SUCCESS),
|
||||
m_SavedTeam(CSaveTeam(Controller)),
|
||||
m_RequestingPlayer(PlayerID)
|
||||
{
|
||||
m_aMessage[0] = '\0';
|
||||
m_aBroadcast[0] = '\0';
|
||||
}
|
||||
enum
|
||||
{
|
||||
SAVE_SUCCESS,
|
||||
// load team in the following two cases
|
||||
SAVE_FAILED,
|
||||
LOAD_SUCCESS,
|
||||
LOAD_FAILED,
|
||||
} m_Status;
|
||||
char m_aMessage[512];
|
||||
char m_aBroadcast[512];
|
||||
CSaveTeam m_SavedTeam;
|
||||
int m_RequestingPlayer;
|
||||
};
|
||||
|
||||
class CSqlMapResult {
|
||||
CSqlMapResult();
|
||||
std::atomic_bool m_Done;
|
||||
};
|
||||
|
||||
// result only valid if m_Done is set to true
|
||||
class CSqlResult
|
||||
{
|
||||
|
@ -128,15 +157,16 @@ struct CSqlTeamScoreData : CSqlData<CSqlResult>
|
|||
sqlstr::CSqlString<MAX_NAME_LENGTH> m_aNames[MAX_CLIENTS];
|
||||
};
|
||||
|
||||
struct CSqlTeamSave : CSqlData<CSqlResult>
|
||||
struct CSqlTeamSave : CSqlData<CSqlSaveResult>
|
||||
{
|
||||
virtual ~CSqlTeamSave();
|
||||
using CSqlData<CSqlSaveResult>::CSqlData;
|
||||
virtual ~CSqlTeamSave() {};
|
||||
|
||||
char m_ClientName[MAX_NAME_LENGTH];
|
||||
CUuid m_SaveUuid;
|
||||
|
||||
sqlstr::CSqlString<128> m_Map;
|
||||
sqlstr::CSqlString<128> m_Code;
|
||||
sqlstr::CSqlString<65536> m_SaveState;
|
||||
char m_Uuid[UUID_MAXSTRSIZE];
|
||||
char m_Server[5];
|
||||
};
|
||||
|
||||
|
@ -185,7 +215,7 @@ class CSqlScore: public IScore
|
|||
|
||||
static bool RandomMapThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure = false);
|
||||
static bool RandomUnfinishedMapThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure = false);
|
||||
static bool MapVoteThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure = false);
|
||||
static bool MapVoteThread(CSqlServer* pSqlServer, const CSqlData<CSqlPlayerResult> *pGameData, bool HandleFailure = false);
|
||||
static bool CheckBirthdayThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure = false);
|
||||
static bool LoadScoreThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure = false);
|
||||
|
||||
|
@ -199,7 +229,7 @@ class CSqlScore: public IScore
|
|||
static bool ShowTopPointsThread(CSqlServer* pSqlServer, const CSqlData<CSqlPlayerResult> *pGameData, bool HandleFailure = false);
|
||||
static bool GetSavesThread(CSqlServer* pSqlServer, const CSqlData<CSqlPlayerResult> *pGameData, bool HandleFailure = false);
|
||||
|
||||
static bool SaveTeamThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure = false);
|
||||
static bool SaveTeamThread(CSqlServer* pSqlServer, const CSqlData<CSqlSaveResult> *pGameData, bool HandleFailure = false);
|
||||
static bool LoadTeamThread(CSqlServer* pSqlServer, const CSqlData<CSqlResult> *pGameData, bool HandleFailure = false);
|
||||
|
||||
static bool SaveScoreThread(CSqlServer* pSqlServer, const CSqlData<CSqlPlayerResult> *pGameData, bool HandleFailure = false);
|
||||
|
@ -253,7 +283,7 @@ public:
|
|||
virtual void GetSaves(int ClientID);
|
||||
|
||||
// requested by teams
|
||||
virtual void SaveTeam(int Team, const char* Code, int ClientID, const char* Server);
|
||||
virtual void SaveTeam(int ClientID, const char* Code, const char* Server);
|
||||
virtual void LoadTeam(const char* Code, int ClientID);
|
||||
|
||||
// Game relevant not allowed to fail
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#include "teams.h"
|
||||
#include "score.h"
|
||||
#include <engine/shared/config.h>
|
||||
#if defined(CONF_SQL)
|
||||
#include "score/sql_score.h"
|
||||
#endif
|
||||
|
||||
CGameTeams::CGameTeams(CGameContext *pGameContext) :
|
||||
m_pGameContext(pGameContext)
|
||||
|
@ -19,9 +22,11 @@ void CGameTeams::Reset()
|
|||
m_MembersCount[i] = 0;
|
||||
m_LastChat[i] = 0;
|
||||
m_TeamLocked[i] = false;
|
||||
m_IsSaving[i] = false;
|
||||
m_Invited[i] = 0;
|
||||
m_Practice[i] = false;
|
||||
#if defined(CONF_SQL)
|
||||
m_pSaveTeamResult[i] = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,7 +257,8 @@ bool CGameTeams::SetCharacterTeam(int ClientID, int Team)
|
|||
|
||||
//you can not join a team which is currently in the process of saving,
|
||||
//because the save-process can fail and then the team is reset into the game
|
||||
if(Team != TEAM_SUPER && m_IsSaving[Team])
|
||||
if((Team != TEAM_SUPER && GetSaving(Team))
|
||||
|| (m_Core.Team(ClientID) != TEAM_SUPER && GetSaving(m_Core.Team(ClientID))))
|
||||
return false;
|
||||
SetForceCharacterTeam(ClientID, Team);
|
||||
|
||||
|
@ -331,6 +337,9 @@ void CGameTeams::ForceLeaveTeam(int ClientID)
|
|||
SetTeamLock(m_Core.Team(ClientID), false);
|
||||
ResetInvited(m_Core.Team(ClientID));
|
||||
m_Practice[m_Core.Team(ClientID)] = false;
|
||||
#if defined(CONF_SQL)
|
||||
m_pSaveTeamResult[m_Core.Team(ClientID)] = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,10 +683,47 @@ void CGameTeams::OnFinish(CPlayer* Player, float Time, const char *pTimestamp)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(CONF_SQL)
|
||||
void CGameTeams::ProcessSaveTeam()
|
||||
{
|
||||
for(int Team = 0; Team < MAX_CLIENTS; Team++)
|
||||
{
|
||||
if(m_pSaveTeamResult[Team] == nullptr || m_pSaveTeamResult[Team].use_count() != 1)
|
||||
continue;
|
||||
if(m_pSaveTeamResult[Team]->m_aBroadcast[0] != '\0')
|
||||
GameServer()->SendBroadcast(m_pSaveTeamResult[Team]->m_aBroadcast, -1);
|
||||
if(m_pSaveTeamResult[Team]->m_aMessage[0] != '\0')
|
||||
GameServer()->SendChatTeam(Team, m_pSaveTeamResult[Team]->m_aMessage);
|
||||
switch(m_pSaveTeamResult[Team]->m_Status)
|
||||
{
|
||||
case CSqlSaveResult::SAVE_SUCCESS:
|
||||
{
|
||||
ResetSavedTeam(m_pSaveTeamResult[Team]->m_RequestingPlayer, Team);
|
||||
break;
|
||||
}
|
||||
case CSqlSaveResult::SAVE_FAILED:
|
||||
{
|
||||
int Result = m_pSaveTeamResult[Team]->m_SavedTeam.load(Team);
|
||||
if(Result != 0)
|
||||
CSaveTeam::HandleLoadError(Result, m_pSaveTeamResult[Team]->m_RequestingPlayer, m_pSaveTeamResult[Team]->m_SavedTeam, m_pGameContext);
|
||||
break;
|
||||
}
|
||||
case CSqlSaveResult::LOAD_SUCCESS:
|
||||
case CSqlSaveResult::LOAD_FAILED:
|
||||
break; // TODO
|
||||
}
|
||||
m_pSaveTeamResult[Team] = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CGameTeams::OnCharacterSpawn(int ClientID)
|
||||
{
|
||||
m_Core.SetSolo(ClientID, false);
|
||||
|
||||
if(GetSaving(m_Core.Team(ClientID)))
|
||||
return;
|
||||
|
||||
if (m_Core.Team(ClientID) >= TEAM_SUPER || !m_TeamLocked[m_Core.Team(ClientID)])
|
||||
// Important to only set a new team here, don't remove from an existing
|
||||
// team since a newly joined player does by definition not have an old team
|
||||
|
@ -690,6 +736,8 @@ void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
|
|||
m_Core.SetSolo(ClientID, false);
|
||||
|
||||
int Team = m_Core.Team(ClientID);
|
||||
if(GetSaving(Team))
|
||||
return;
|
||||
bool Locked = TeamLocked(Team) && Weapon != WEAPON_GAME;
|
||||
|
||||
if(!Locked)
|
||||
|
@ -750,30 +798,27 @@ void CGameTeams::SetClientInvited(int Team, int ClientID, bool Invited)
|
|||
}
|
||||
}
|
||||
|
||||
void CGameTeams::KillSavedTeam(int Team)
|
||||
#if defined(CONF_SQL)
|
||||
void CGameTeams::KillSavedTeam(int ClientID, int Team)
|
||||
{
|
||||
// Set so that no finish is accidentally given to some of the players
|
||||
ChangeTeamState(Team, CGameTeams::TEAMSTATE_OPEN);
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
{
|
||||
GameServer()->m_apPlayers[i]->m_VotedForPractice = false;
|
||||
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameTeams::ResetSavedTeam(int ClientID, int Team)
|
||||
{
|
||||
for (int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
{
|
||||
// Set so that no finish is accidentally given to some of the players
|
||||
GameServer()->m_apPlayers[i]->GetCharacter()->m_DDRaceState = DDRACE_NONE;
|
||||
m_TeeFinished[i] = false;
|
||||
SetForceCharacterTeam(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
GameServer()->m_apPlayers[i]->ThreadKillCharacter(-2);
|
||||
|
||||
ChangeTeamState(Team, CGameTeams::TEAMSTATE_EMPTY);
|
||||
|
||||
// unlock team when last player leaves
|
||||
SetTeamLock(Team, false);
|
||||
ResetInvited(Team);
|
||||
|
||||
m_Practice[Team] = false;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -5,15 +5,21 @@
|
|||
#include <game/teamscore.h>
|
||||
#include <game/server/gamecontext.h>
|
||||
|
||||
#if defined(CONF_SQL)
|
||||
class CSqlSaveResult;
|
||||
#endif
|
||||
|
||||
class CGameTeams
|
||||
{
|
||||
int m_TeamState[MAX_CLIENTS];
|
||||
int m_MembersCount[MAX_CLIENTS];
|
||||
bool m_TeeFinished[MAX_CLIENTS];
|
||||
bool m_TeamLocked[MAX_CLIENTS];
|
||||
bool m_IsSaving[MAX_CLIENTS];
|
||||
uint64_t m_Invited[MAX_CLIENTS];
|
||||
bool m_Practice[MAX_CLIENTS];
|
||||
#if defined(CONF_SQL)
|
||||
std::shared_ptr<CSqlSaveResult> m_pSaveTeamResult[MAX_CLIENTS];
|
||||
#endif
|
||||
|
||||
class CGameContext * m_pGameContext;
|
||||
|
||||
|
@ -85,7 +91,11 @@ public:
|
|||
void SetDDRaceState(CPlayer* Player, int DDRaceState);
|
||||
void SetStartTime(CPlayer* Player, int StartTime);
|
||||
void SetCpActive(CPlayer* Player, int CpActive);
|
||||
void KillSavedTeam(int Team);
|
||||
#if defined(CONF_SQL)
|
||||
void KillSavedTeam(int ClientID, int Team);
|
||||
void ResetSavedTeam(int ClientID, int Team);
|
||||
void ProcessSaveTeam();
|
||||
#endif
|
||||
|
||||
bool TeeFinished(int ClientID)
|
||||
{
|
||||
|
@ -114,15 +124,20 @@ public:
|
|||
{
|
||||
m_TeeFinished[ClientID] = finished;
|
||||
}
|
||||
|
||||
void SetSaving(int TeamID, bool Value)
|
||||
#if defined(CONF_SQL)
|
||||
void SetSaving(int TeamID, std::shared_ptr<CSqlSaveResult> SaveResult)
|
||||
{
|
||||
m_IsSaving[TeamID] = Value;
|
||||
m_pSaveTeamResult[TeamID] = SaveResult;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GetSaving(int TeamID)
|
||||
{
|
||||
return m_IsSaving[TeamID];
|
||||
#if defined(CONF_SQL)
|
||||
return m_pSaveTeamResult[TeamID] != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnablePractice(int Team)
|
||||
|
|
Loading…
Reference in a new issue