mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Add /save by the glorious HMH
This commit is contained in:
parent
5864a47c4b
commit
145f0434f5
|
@ -195,6 +195,7 @@ MACRO_CONFIG_STR(SvSqlIp, sv_sql_ip, 32, "127.0.0.1", CFGFLAG_SERVER, "SQL Datab
|
|||
MACRO_CONFIG_INT(SvSqlPort, sv_sql_port, 3306, 0, 65535, CFGFLAG_SERVER, "SQL Database port")
|
||||
MACRO_CONFIG_STR(SvSqlDatabase, sv_sql_database, 16, "teeworlds", CFGFLAG_SERVER, "SQL Database name")
|
||||
MACRO_CONFIG_STR(SvSqlPrefix, sv_sql_prefix, 16, "record", CFGFLAG_SERVER, "SQL Database table prefix")
|
||||
MACRO_CONFIG_INT(SvSaveGames, sv_savegames, 1, 0, 1, CFGFLAG_SERVER, "Enables savegames (/save and /load)")
|
||||
#endif
|
||||
|
||||
MACRO_CONFIG_INT(SvDDRaceRules, sv_ddrace_rules, 1, 0, 1, CFGFLAG_SERVER, "Whether the default mod rules are displayed or not")
|
||||
|
|
|
@ -565,6 +565,70 @@ void CGameContext::ConMapPoints(IConsole::IResult *pResult, void *pUserData)
|
|||
#endif
|
||||
}
|
||||
|
||||
void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CGameContext *pSelf = (CGameContext *) pUserData;
|
||||
if (!CheckClientID(pResult->m_ClientID))
|
||||
return;
|
||||
|
||||
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
|
||||
if (!pPlayer)
|
||||
return;
|
||||
|
||||
#if defined(CONF_SQL)
|
||||
if(!g_Config.m_SvSaveGames)
|
||||
{
|
||||
pSelf->SendChatTarget(pResult->m_ClientID, "Save-function is disabled on this server");
|
||||
return;
|
||||
}
|
||||
|
||||
if(g_Config.m_SvUseSQL)
|
||||
if(pPlayer->m_LastSQLQuery + pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick())
|
||||
return;
|
||||
#endif
|
||||
|
||||
int Team = ((CGameControllerDDRace*) pSelf->m_pController)->m_Teams.m_Core.Team(pResult->m_ClientID);
|
||||
pSelf->Score()->SaveTeam(Team, pResult->GetString(0), pResult->m_ClientID);
|
||||
|
||||
#if defined(CONF_SQL)
|
||||
if(g_Config.m_SvUseSQL)
|
||||
pPlayer->m_LastSQLQuery = pSelf->Server()->Tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGameContext::ConLoad(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CGameContext *pSelf = (CGameContext *) pUserData;
|
||||
if (!CheckClientID(pResult->m_ClientID))
|
||||
return;
|
||||
|
||||
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
|
||||
if (!pPlayer)
|
||||
return;
|
||||
|
||||
#if defined(CONF_SQL)
|
||||
if(!g_Config.m_SvSaveGames)
|
||||
{
|
||||
pSelf->SendChatTarget(pResult->m_ClientID, "Save-function is disabled on this server");
|
||||
return;
|
||||
}
|
||||
|
||||
if(g_Config.m_SvUseSQL)
|
||||
if(pPlayer->m_LastSQLQuery + pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick())
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (pResult->NumArguments() > 0)
|
||||
pSelf->Score()->LoadTeam(pResult->GetString(0), pResult->m_ClientID);
|
||||
else
|
||||
return;
|
||||
|
||||
#if defined(CONF_SQL)
|
||||
if(g_Config.m_SvUseSQL)
|
||||
pPlayer->m_LastSQLQuery = pSelf->Server()->Tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGameContext::ConTeamRank(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CGameContext *pSelf = (CGameContext *) pUserData;
|
||||
|
|
|
@ -21,6 +21,8 @@ CHAT_COMMAND("pause", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTogglePause, this, "To
|
|||
CHAT_COMMAND("spec", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConToggleSpec, this, "Toggles spec")
|
||||
CHAT_COMMAND("dnd", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConDND, this, "Toggle Do Not Disturb (no chat and server messages)")
|
||||
CHAT_COMMAND("mapinfo", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConMapPoints, this, "Show info about the map with name r gives (current map by default)")
|
||||
CHAT_COMMAND("save", "s", CFGFLAG_CHAT|CFGFLAG_SERVER, ConSave, this, "Save team with code s")
|
||||
CHAT_COMMAND("load", "s", CFGFLAG_CHAT|CFGFLAG_SERVER, ConLoad, this, "Load with code s")
|
||||
CHAT_COMMAND("map", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConMap, this, "Vote a map by name")
|
||||
CHAT_COMMAND("rankteam", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTeamRank, this, "Shows the team rank of player with name r (your team rank by default)")
|
||||
CHAT_COMMAND("rank", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConRank, this, "Shows the rank of player with name r (your rank by default)")
|
||||
|
|
|
@ -32,6 +32,8 @@ class CCharacter : public CEntity
|
|||
{
|
||||
MACRO_ALLOC_POOL_ID()
|
||||
|
||||
friend class CSaveTee; // need to use core
|
||||
|
||||
public:
|
||||
//character's size
|
||||
static const int ms_PhysSize = 28;
|
||||
|
|
|
@ -281,6 +281,13 @@ void CGameContext::SendChatTarget(int To, const char *pText)
|
|||
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, To);
|
||||
}
|
||||
|
||||
void CGameContext::SendChatTeam(int Team, const char *pText)
|
||||
{
|
||||
for(int i = 0; i<MAX_CLIENTS; i++)
|
||||
if(((CGameControllerDDRace*)m_pController)->m_Teams.m_Core.Team(i) == Team)
|
||||
SendChatTarget(i, pText);
|
||||
}
|
||||
|
||||
void CGameContext::SendChat(int ChatterClientID, int Team, const char *pText, int SpamProtectionClientID)
|
||||
{
|
||||
if(SpamProtectionClientID >= 0 && SpamProtectionClientID < MAX_CLIENTS)
|
||||
|
|
|
@ -67,6 +67,8 @@ class CGameContext : public IGameServer
|
|||
static void ConChangeMap(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConRandomMap(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConRandomUnfinishedMap(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConSaveTeam(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConLoadTeam(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConRestart(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConBroadcast(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConSay(IConsole::IResult *pResult, void *pUserData);
|
||||
|
@ -161,6 +163,7 @@ public:
|
|||
// network
|
||||
void CallVote(int ClientID, const char *aDesc, const char *aCmd, const char *pReason, const char *aChatmsg);
|
||||
void SendChatTarget(int To, const char *pText);
|
||||
void SendChatTeam(int Team, const char *pText);
|
||||
void SendChat(int ClientID, int Team, const char *pText, int SpamProtectionClientID = -1);
|
||||
void SendEmoticon(int ClientID, int Emoticon);
|
||||
void SendWeaponPickup(int ClientID, int Weapon);
|
||||
|
@ -266,6 +269,8 @@ private:
|
|||
static void ConUTF8(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConDND(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConMapPoints(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConSave(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConLoad(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConMap(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConTeamRank(IConsole::IResult *pResult, void *pUserData);
|
||||
static void ConRank(IConsole::IResult *pResult, void *pUserData);
|
||||
|
|
|
@ -22,6 +22,8 @@ typedef unsigned __int64 uint64_t;
|
|||
*/
|
||||
class IGameController
|
||||
{
|
||||
friend class CSaveTeam; // need acces to GameServer() and Server()
|
||||
|
||||
vec2 m_aaSpawnPoints[3][64];
|
||||
int m_aNumSpawnPoints[3];
|
||||
|
||||
|
|
|
@ -403,6 +403,15 @@ void CPlayer::Respawn()
|
|||
m_Spawning = true;
|
||||
}
|
||||
|
||||
CCharacter* CPlayer::ForceSpawn(vec2 Pos)
|
||||
{
|
||||
m_Spawning = false;
|
||||
m_pCharacter = new(m_ClientID) CCharacter(&GameServer()->m_World);
|
||||
m_pCharacter->Spawn(this, Pos);
|
||||
m_Team = 0;
|
||||
return m_pCharacter;
|
||||
}
|
||||
|
||||
void CPlayer::SetTeam(int Team, bool DoChatMsg)
|
||||
{
|
||||
// clamp the team
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
class CPlayer
|
||||
{
|
||||
MACRO_ALLOC_POOL_ID()
|
||||
|
||||
friend class CSaveTee;
|
||||
|
||||
public:
|
||||
CPlayer(CGameContext *pGameServer, int ClientID, int Team);
|
||||
|
@ -20,6 +22,7 @@ public:
|
|||
|
||||
void TryRespawn();
|
||||
void Respawn();
|
||||
CCharacter* ForceSpawn(vec2 Pos); // required for loading savegames
|
||||
void SetTeam(int Team, bool DoChatMsg=true);
|
||||
int GetTeam() const { return m_Team; };
|
||||
int GetCID() const { return m_ClientID; };
|
||||
|
|
499
src/game/server/save.cpp
Normal file
499
src/game/server/save.cpp
Normal file
|
@ -0,0 +1,499 @@
|
|||
#include <new>
|
||||
#include <cstdio>
|
||||
|
||||
#include "save.h"
|
||||
#include "teams.h"
|
||||
#include <engine/server/server.h>
|
||||
#include "./gamemodes/DDRace.h"
|
||||
|
||||
CSaveTee::CSaveTee()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
CSaveTee::~CSaveTee()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void CSaveTee::save(CCharacter* pchr)
|
||||
{
|
||||
str_copy(m_name, pchr->m_pPlayer->Server()->ClientName(pchr->m_pPlayer->GetCID()), sizeof(m_name));
|
||||
|
||||
m_Alive = pchr->m_Alive;
|
||||
m_Paused = pchr->m_pPlayer->m_Paused;
|
||||
m_NeededFaketuning = pchr->m_NeededFaketuning;
|
||||
|
||||
m_TeeFinished = pchr->Teams()->TeeFinished(pchr->m_pPlayer->GetCID());
|
||||
m_IsSolo = pchr->Teams()->m_Core.GetSolo(pchr->m_pPlayer->GetCID());
|
||||
|
||||
for(int i = 0; i< NUM_WEAPONS; i++)
|
||||
{
|
||||
m_aWeapons[i].m_AmmoRegenStart = pchr->m_aWeapons[i].m_AmmoRegenStart;
|
||||
m_aWeapons[i].m_Ammo = pchr->m_aWeapons[i].m_Ammo;
|
||||
m_aWeapons[i].m_Ammocost = pchr->m_aWeapons[i].m_Ammocost;
|
||||
m_aWeapons[i].m_Got = pchr->m_aWeapons[i].m_Got;
|
||||
}
|
||||
|
||||
m_LastWeapon = pchr->m_LastWeapon;
|
||||
m_QueuedWeapon = pchr->m_QueuedWeapon;
|
||||
|
||||
m_SuperJump = pchr->m_SuperJump;
|
||||
m_Jetpack = pchr->m_Jetpack;
|
||||
m_NinjaJetpack = pchr->m_NinjaJetpack;
|
||||
m_FreezeTime = pchr->m_FreezeTime;
|
||||
|
||||
if(pchr->m_FreezeTick)
|
||||
m_FreezeTick = pchr->Server()->Tick() - pchr->m_FreezeTick;
|
||||
|
||||
m_DeepFreeze = pchr->m_DeepFreeze;
|
||||
m_EndlessHook = pchr->m_EndlessHook;
|
||||
m_DDRaceState = pchr->m_DDRaceState;
|
||||
|
||||
m_Hit = pchr->m_Hit;
|
||||
m_Collision = pchr->m_Collision;
|
||||
m_TuneZone = pchr->m_TuneZone;
|
||||
m_TuneZoneOld = pchr->m_TuneZoneOld;
|
||||
m_Hook = pchr->m_Hook;
|
||||
|
||||
if(pchr->m_StartTime)
|
||||
m_Time = pchr->Server()->Tick() - pchr->m_StartTime;
|
||||
|
||||
m_Pos = pchr->m_Pos;
|
||||
m_PrevPos = pchr->m_PrevPos;
|
||||
m_TeleCheckpoint = pchr->m_TeleCheckpoint;
|
||||
m_LastPenalty = pchr->m_LastPenalty;
|
||||
|
||||
if(pchr->m_CpTick)
|
||||
m_CpTime = pchr->Server()->Tick() - pchr->m_CpTick;
|
||||
|
||||
m_CpActive = pchr->m_CpActive;
|
||||
m_CpLastBroadcast = pchr->m_CpLastBroadcast;
|
||||
|
||||
for(int i = 0; i<=25; i++)
|
||||
m_CpCurrent[i] = pchr->m_CpCurrent[i];
|
||||
|
||||
// Core
|
||||
m_CorePos = pchr->m_Core.m_Pos;
|
||||
m_Vel = pchr->m_Core.m_Vel;
|
||||
m_ActiveWeapon = pchr->m_Core.m_ActiveWeapon;
|
||||
m_Jumped = pchr->m_Core.m_Jumped;
|
||||
m_JumpedTotal = pchr->m_Core.m_JumpedTotal;
|
||||
m_Jumps = pchr->m_Core.m_Jumps;
|
||||
m_HookPos = pchr->m_Core.m_HookPos;
|
||||
m_HookDir = pchr->m_Core.m_HookDir;
|
||||
m_HookTeleBase = pchr->m_Core.m_HookTeleBase;
|
||||
|
||||
m_HookTick = pchr->m_Core.m_HookTick;
|
||||
|
||||
m_HookState = pchr->m_Core.m_HookState;
|
||||
}
|
||||
|
||||
void CSaveTee::load(CCharacter* pchr, int Team)
|
||||
{
|
||||
pchr->m_pPlayer->m_Paused = m_Paused;
|
||||
pchr->m_pPlayer->ProcessPause();
|
||||
|
||||
pchr->m_Alive = m_Alive;
|
||||
pchr->m_NeededFaketuning = m_NeededFaketuning;
|
||||
|
||||
pchr->Teams()->SetForceCharacterTeam(pchr->m_pPlayer->GetCID(), Team);
|
||||
pchr->Teams()->m_Core.SetSolo(pchr->m_pPlayer->GetCID(), m_IsSolo);
|
||||
pchr->Teams()->SetFinished(pchr->m_pPlayer->GetCID(), m_TeeFinished);
|
||||
|
||||
for(int i = 0; i< NUM_WEAPONS; i++)
|
||||
{
|
||||
pchr->m_aWeapons[i].m_AmmoRegenStart = m_aWeapons[i].m_AmmoRegenStart;
|
||||
pchr->m_aWeapons[i].m_Ammo = m_aWeapons[i].m_Ammo;
|
||||
pchr->m_aWeapons[i].m_Ammocost = m_aWeapons[i].m_Ammocost;
|
||||
pchr->m_aWeapons[i].m_Got = m_aWeapons[i].m_Got;
|
||||
}
|
||||
|
||||
pchr->m_LastWeapon = m_LastWeapon;
|
||||
pchr->m_QueuedWeapon = m_QueuedWeapon;
|
||||
|
||||
pchr->m_SuperJump = m_SuperJump;
|
||||
pchr->m_Jetpack = m_Jetpack;
|
||||
pchr->m_NinjaJetpack = m_NinjaJetpack;
|
||||
pchr->m_FreezeTime = m_FreezeTime;
|
||||
|
||||
if(m_FreezeTick)
|
||||
pchr->m_FreezeTick = pchr->Server()->Tick() - m_FreezeTick;
|
||||
|
||||
pchr->m_DeepFreeze = m_DeepFreeze;
|
||||
pchr->m_EndlessHook = m_EndlessHook;
|
||||
pchr->m_DDRaceState = m_DDRaceState;
|
||||
|
||||
pchr->m_Hit = m_Hit;
|
||||
pchr->m_Collision = m_Collision;
|
||||
pchr->m_TuneZone = m_TuneZone;
|
||||
pchr->m_TuneZoneOld = m_TuneZoneOld;
|
||||
pchr->m_Hook = m_Hook;
|
||||
|
||||
if(m_Time)
|
||||
pchr->m_StartTime = pchr->Server()->Tick() - m_Time;
|
||||
|
||||
pchr->m_Pos = m_Pos;
|
||||
pchr->m_PrevPos = m_PrevPos;
|
||||
pchr->m_TeleCheckpoint = m_TeleCheckpoint;
|
||||
pchr->m_LastPenalty = m_LastPenalty;
|
||||
|
||||
if(m_CpTime)
|
||||
pchr->m_CpTick = pchr->Server()->Tick() - m_CpTime;
|
||||
|
||||
pchr->m_CpActive = m_CpActive;
|
||||
pchr->m_CpLastBroadcast = m_CpLastBroadcast;
|
||||
|
||||
for(int i = 0; i<=25; i++)
|
||||
pchr->m_CpCurrent[i] =m_CpCurrent[i];
|
||||
|
||||
// Core
|
||||
pchr->m_Core.m_Pos = m_CorePos;
|
||||
pchr->m_Core.m_Vel = m_Vel;
|
||||
pchr->m_Core.m_ActiveWeapon = m_ActiveWeapon;
|
||||
pchr->m_Core.m_Jumped = m_Jumped;
|
||||
pchr->m_Core.m_JumpedTotal = m_JumpedTotal;
|
||||
pchr->m_Core.m_Jumps = m_Jumps;
|
||||
pchr->m_Core.m_HookPos = m_HookPos;
|
||||
pchr->m_Core.m_HookDir = m_HookDir;
|
||||
pchr->m_Core.m_HookTeleBase = m_HookTeleBase;
|
||||
|
||||
pchr->m_Core.m_HookTick = m_HookTick;
|
||||
|
||||
if(m_HookState == HOOK_GRABBED)
|
||||
{
|
||||
pchr->m_Core.m_HookState = HOOK_FLYING;
|
||||
pchr->m_Core.m_HookedPlayer = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pchr->m_Core.m_HookState = m_HookState;
|
||||
}
|
||||
}
|
||||
|
||||
char* CSaveTee::GetString()
|
||||
{
|
||||
str_format(m_String, sizeof(m_String), "%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%f\t%f\t%d\t%d\t%d\t%d\t%d\t%d\t%f\t%f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f", m_name, m_Alive, m_Paused, m_NeededFaketuning, m_TeeFinished, m_IsSolo, m_aWeapons[0].m_AmmoRegenStart, m_aWeapons[0].m_Ammo, m_aWeapons[0].m_Ammocost, m_aWeapons[0].m_Got, m_aWeapons[1].m_AmmoRegenStart, m_aWeapons[1].m_Ammo, m_aWeapons[1].m_Ammocost, m_aWeapons[1].m_Got, m_aWeapons[2].m_AmmoRegenStart, m_aWeapons[2].m_Ammo, m_aWeapons[2].m_Ammocost, m_aWeapons[2].m_Got, m_aWeapons[3].m_AmmoRegenStart, m_aWeapons[3].m_Ammo, m_aWeapons[3].m_Ammocost, m_aWeapons[3].m_Got, m_aWeapons[4].m_AmmoRegenStart, m_aWeapons[4].m_Ammo, m_aWeapons[4].m_Ammocost, m_aWeapons[4].m_Got, m_aWeapons[5].m_AmmoRegenStart, m_aWeapons[5].m_Ammo, m_aWeapons[5].m_Ammocost, m_aWeapons[5].m_Got, m_LastWeapon, m_QueuedWeapon, m_SuperJump, m_Jetpack, m_NinjaJetpack, m_FreezeTime, m_DeepFreeze, m_EndlessHook, m_DDRaceState, m_Hit, m_Collision, m_TuneZone, m_TuneZoneOld, m_Hook, m_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, m_ActiveWeapon, m_Jumped, m_JumpedTotal, m_Jumps, (int)m_HookPos.x, (int)m_HookPos.y, m_HookDir.x, m_HookDir.y, (int)m_HookTeleBase.x, (int)m_HookTeleBase.y, m_HookTick, m_HookState, m_CpTime, m_CpActive, m_CpLastBroadcast, m_CpCurrent[0], m_CpCurrent[1], m_CpCurrent[2], m_CpCurrent[3], m_CpCurrent[4], m_CpCurrent[5], m_CpCurrent[6], m_CpCurrent[7], m_CpCurrent[8], m_CpCurrent[9], m_CpCurrent[10], m_CpCurrent[11], m_CpCurrent[12], m_CpCurrent[13], m_CpCurrent[14], m_CpCurrent[15], m_CpCurrent[16], m_CpCurrent[17], m_CpCurrent[18], m_CpCurrent[19], m_CpCurrent[20], m_CpCurrent[21], m_CpCurrent[22], m_CpCurrent[23], m_CpCurrent[24]);
|
||||
return m_String;
|
||||
}
|
||||
|
||||
int CSaveTee::LoadString(char* String)
|
||||
{
|
||||
int Num;
|
||||
Num = sscanf(String, "%[^\t]\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%f\t%f\t%f\t%f\t%d\t%d\t%f\t%f\t%f\t%f\t%d\t%d\t%d\t%d\t%f\t%f\t%f\t%f\t%f\t%f\t%d\t%d\t%d\t%d\t%d\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f", m_name, &m_Alive, &m_Paused, &m_NeededFaketuning, &m_TeeFinished, &m_IsSolo, &m_aWeapons[0].m_AmmoRegenStart, &m_aWeapons[0].m_Ammo, &m_aWeapons[0].m_Ammocost, &m_aWeapons[0].m_Got, &m_aWeapons[1].m_AmmoRegenStart, &m_aWeapons[1].m_Ammo, &m_aWeapons[1].m_Ammocost, &m_aWeapons[1].m_Got, &m_aWeapons[2].m_AmmoRegenStart, &m_aWeapons[2].m_Ammo, &m_aWeapons[2].m_Ammocost, &m_aWeapons[2].m_Got, &m_aWeapons[3].m_AmmoRegenStart, &m_aWeapons[3].m_Ammo, &m_aWeapons[3].m_Ammocost, &m_aWeapons[3].m_Got, &m_aWeapons[4].m_AmmoRegenStart, &m_aWeapons[4].m_Ammo, &m_aWeapons[4].m_Ammocost, &m_aWeapons[4].m_Got, &m_aWeapons[5].m_AmmoRegenStart, &m_aWeapons[5].m_Ammo, &m_aWeapons[5].m_Ammocost, &m_aWeapons[5].m_Got, &m_LastWeapon, &m_QueuedWeapon, &m_SuperJump, &m_Jetpack, &m_NinjaJetpack, &m_FreezeTime, &m_DeepFreeze, &m_EndlessHook, &m_DDRaceState, &m_Hit, &m_Collision, &m_TuneZone, &m_TuneZoneOld, &m_Hook, &m_Time, &m_Pos.x, &m_Pos.y, &m_PrevPos.x, &m_PrevPos.y, &m_TeleCheckpoint, &m_LastPenalty, &m_CorePos.x, &m_CorePos.y, &m_Vel.x, &m_Vel.y, &m_ActiveWeapon, &m_Jumped, &m_JumpedTotal, &m_Jumps, &m_HookPos.x, &m_HookPos.y, &m_HookDir.x, &m_HookDir.y, &m_HookTeleBase.x, &m_HookTeleBase.y, &m_HookTick, &m_HookState, &m_CpTime, &m_CpActive, &m_CpLastBroadcast, &m_CpCurrent[0], &m_CpCurrent[1], &m_CpCurrent[2], &m_CpCurrent[3], &m_CpCurrent[4], &m_CpCurrent[5], &m_CpCurrent[6], &m_CpCurrent[7], &m_CpCurrent[8], &m_CpCurrent[9], &m_CpCurrent[10], &m_CpCurrent[11], &m_CpCurrent[12], &m_CpCurrent[13], &m_CpCurrent[14], &m_CpCurrent[15], &m_CpCurrent[16], &m_CpCurrent[17], &m_CpCurrent[18], &m_CpCurrent[19], &m_CpCurrent[20], &m_CpCurrent[21], &m_CpCurrent[22], &m_CpCurrent[23], &m_CpCurrent[24]);
|
||||
if (Num == 95)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
dbg_msg("Load", "failed to load Tee-string");
|
||||
char aBuf[32];
|
||||
str_format(aBuf, sizeof(aBuf), "loaded %d vars", Num);
|
||||
dbg_msg("Load", aBuf);
|
||||
return Num+1; // never 0 here
|
||||
}
|
||||
}
|
||||
|
||||
CSaveTeam::CSaveTeam(IGameController* Controller)
|
||||
{
|
||||
m_pController = Controller;
|
||||
m_Switchers = 0;
|
||||
SavedTees = 0;
|
||||
}
|
||||
|
||||
CSaveTeam::~CSaveTeam()
|
||||
{
|
||||
if(m_Switchers)
|
||||
delete[] m_Switchers;
|
||||
if(SavedTees)
|
||||
delete[] SavedTees;
|
||||
}
|
||||
|
||||
int CSaveTeam::save(int Team)
|
||||
{
|
||||
if(Team > 0 && Team < 64)
|
||||
{
|
||||
CGameTeams* Teams = &(((CGameControllerDDRace*)m_pController)->m_Teams);
|
||||
|
||||
if(Teams->Count(Team) <= 0)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
m_TeamState = Teams->GetTeamState(Team);
|
||||
m_MembersCount = Teams->Count(Team);
|
||||
m_NumSwitchers = m_pController->GameServer()->Collision()->m_NumSwitchers;
|
||||
m_TeamLocked = Teams->TeamLocked(Team);
|
||||
|
||||
SavedTees = new CSaveTee[m_MembersCount];
|
||||
int j = 0;
|
||||
for (int i = 0; i<64; i++)
|
||||
{
|
||||
if(Teams->m_Core.Team(i) == Team)
|
||||
{
|
||||
if(m_pController->GameServer()->m_apPlayers[i]->GetCharacter())
|
||||
SavedTees[j].save(m_pController->GameServer()->m_apPlayers[i]->GetCharacter());
|
||||
else
|
||||
return 3;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_pController->GameServer()->Collision()->m_NumSwitchers)
|
||||
{
|
||||
m_Switchers = new SSimpleSwitchers[m_pController->GameServer()->Collision()->m_NumSwitchers+1];
|
||||
|
||||
for(int i=1; i < m_pController->GameServer()->Collision()->m_NumSwitchers+1; i++)
|
||||
{
|
||||
m_Switchers[i].m_Status = m_pController->GameServer()->Collision()->m_pSwitchers[i].m_Status[Team];
|
||||
if(m_pController->GameServer()->Collision()->m_pSwitchers[i].m_EndTick[Team])
|
||||
m_Switchers[i].m_EndTime = m_pController->Server()->Tick() - m_pController->GameServer()->Collision()->m_pSwitchers[i].m_EndTick[Team];
|
||||
else
|
||||
m_Switchers[i].m_EndTime = 0;
|
||||
m_Switchers[i].m_Type = m_pController->GameServer()->Collision()->m_pSwitchers[i].m_Type[Team];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CSaveTeam::load(int Team)
|
||||
{
|
||||
if(Team > 0 && Team < 64)
|
||||
{
|
||||
CGameTeams* Teams = &(((CGameControllerDDRace*)m_pController)->m_Teams);
|
||||
|
||||
Teams->ChangeTeamState(Team, m_TeamState);
|
||||
Teams->SetTeamLock(Team, m_TeamLocked);
|
||||
|
||||
CCharacter* pchr;
|
||||
|
||||
for (int i = 0; i<m_MembersCount; i++)
|
||||
{
|
||||
int ID = MatchPlayer(SavedTees[i].GetName());
|
||||
if(ID == -1) // first check if team can be loaded / do not load half teams
|
||||
{
|
||||
return i+10; // +10 to let space for other return-values
|
||||
}
|
||||
else if (m_pController->GameServer()->m_apPlayers[ID]->GetCharacter() && m_pController->GameServer()->m_apPlayers[ID]->GetCharacter()->m_DDRaceState)
|
||||
{
|
||||
return i+100; // +100 to let space for other return-values
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i<m_MembersCount; i++)
|
||||
{
|
||||
pchr = MatchCharacter(SavedTees[i].GetName(), i);
|
||||
if(pchr)
|
||||
{
|
||||
SavedTees[i].load(pchr, Team);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_pController->GameServer()->Collision()->m_NumSwitchers)
|
||||
for(int i=1; i < m_pController->GameServer()->Collision()->m_NumSwitchers+1; i++)
|
||||
{
|
||||
m_pController->GameServer()->Collision()->m_pSwitchers[i].m_Status[Team] = m_Switchers[i].m_Status;
|
||||
if(m_Switchers[i].m_EndTime)
|
||||
m_pController->GameServer()->Collision()->m_pSwitchers[i].m_EndTick[Team] = m_pController->Server()->Tick() - m_Switchers[i].m_EndTime;
|
||||
m_pController->GameServer()->Collision()->m_pSwitchers[i].m_Type[Team] = m_Switchers[i].m_Type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CSaveTeam::MatchPlayer(char name[16])
|
||||
{
|
||||
for (int i = 0; i<64; i++)
|
||||
{
|
||||
if(str_comp(m_pController->Server()->ClientName(i), name) == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
CCharacter* CSaveTeam::MatchCharacter(char name[16], int SaveID)
|
||||
{
|
||||
int ID = MatchPlayer(name);
|
||||
if(ID >= 0)
|
||||
{
|
||||
if(m_pController->GameServer()->m_apPlayers[ID]->GetCharacter())
|
||||
return m_pController->GameServer()->m_apPlayers[ID]->GetCharacter();
|
||||
else
|
||||
return m_pController->GameServer()->m_apPlayers[ID]->ForceSpawn(SavedTees[SaveID].GetPos());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* CSaveTeam::GetString()
|
||||
{
|
||||
str_format(m_String, sizeof(m_String), "%d\t%d\t%d\t%d", m_TeamState, m_MembersCount, m_NumSwitchers, m_TeamLocked);
|
||||
|
||||
for (int i = 0; i<m_MembersCount; i++)
|
||||
{
|
||||
char aBuf[1024];
|
||||
str_format(aBuf, sizeof(aBuf), "\n%s", SavedTees[i].GetString());
|
||||
str_append(m_String, aBuf, sizeof(m_String));
|
||||
}
|
||||
|
||||
if(m_NumSwitchers)
|
||||
for(int i=1; i < m_NumSwitchers+1; i++)
|
||||
{
|
||||
char aBuf[64];
|
||||
str_format(aBuf, sizeof(aBuf), "\n%d\t%d\t%d", m_Switchers[i].m_Status, m_Switchers[i].m_EndTime, m_Switchers[i].m_Type);
|
||||
str_append(m_String, aBuf, sizeof(m_String));
|
||||
}
|
||||
|
||||
return m_String;
|
||||
}
|
||||
|
||||
int CSaveTeam::LoadString(const char* String)
|
||||
{
|
||||
char TeamStats[64];
|
||||
char Switcher[64];
|
||||
char SaveTee[1024];
|
||||
|
||||
char* CopyPos;
|
||||
unsigned int Pos = 0;
|
||||
unsigned int LastPos = 0;
|
||||
unsigned int StrSize;
|
||||
|
||||
str_copy(m_String, String, sizeof(m_String));
|
||||
|
||||
while (m_String[Pos] != '\n' && Pos < sizeof(m_String) && m_String[Pos]) // find next \n or \0
|
||||
Pos++;
|
||||
|
||||
CopyPos = m_String + LastPos;
|
||||
StrSize = Pos - LastPos + 1;
|
||||
if(m_String[Pos] == '\n')
|
||||
{
|
||||
Pos++; // skip \n
|
||||
LastPos = Pos;
|
||||
}
|
||||
|
||||
if(StrSize <= 0)
|
||||
{
|
||||
dbg_msg("Load", "Savegame: wrong format (couldn't load TeamStats)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(StrSize < sizeof(TeamStats))
|
||||
{
|
||||
str_copy(TeamStats, CopyPos, StrSize);
|
||||
int Num = sscanf(TeamStats, "%d\t%d\t%d\t%d", &m_TeamState, &m_MembersCount, &m_NumSwitchers, &m_TeamLocked);
|
||||
if(Num != 4)
|
||||
{
|
||||
dbg_msg("Load", "failed to load Teamstats");
|
||||
char aBuf[32];
|
||||
str_format(aBuf, sizeof(aBuf), "loaded %d vars", Num);
|
||||
dbg_msg("Load", aBuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("Load", "Savegame: wrong format (couldn't load TeamStats, too big)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(SavedTees)
|
||||
{
|
||||
delete [] SavedTees;
|
||||
SavedTees = 0;
|
||||
}
|
||||
|
||||
if(m_MembersCount)
|
||||
SavedTees = new CSaveTee[m_MembersCount];
|
||||
|
||||
for (int n = 0; n < m_MembersCount; n++)
|
||||
{
|
||||
while (m_String[Pos] != '\n' && Pos < sizeof(m_String) && m_String[Pos]) // find next \n or \0
|
||||
Pos++;
|
||||
|
||||
CopyPos = m_String + LastPos;
|
||||
StrSize = Pos - LastPos + 1;
|
||||
if(m_String[Pos] == '\n')
|
||||
{
|
||||
Pos++; // skip \n
|
||||
LastPos = Pos;
|
||||
}
|
||||
|
||||
if(StrSize <= 0)
|
||||
{
|
||||
dbg_msg("Load", "Savegame: wrong format (couldn't load Tee)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(StrSize < sizeof(SaveTee))
|
||||
{
|
||||
str_copy(SaveTee, CopyPos, StrSize);
|
||||
int Num = SavedTees[n].LoadString(SaveTee);
|
||||
if(Num)
|
||||
{
|
||||
dbg_msg("Load", "failed to load Tee");
|
||||
char aBuf[32];
|
||||
str_format(aBuf, sizeof(aBuf), "loaded %d vars", Num-1);
|
||||
dbg_msg("Load", aBuf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("Load", "Savegame: wrong format (couldn't load Tee, too big)");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_Switchers)
|
||||
{
|
||||
delete [] m_Switchers;
|
||||
m_Switchers = 0;
|
||||
}
|
||||
|
||||
if(m_NumSwitchers)
|
||||
m_Switchers = new SSimpleSwitchers[m_NumSwitchers+1];
|
||||
|
||||
for (int n = 1; n < m_NumSwitchers+1; n++)
|
||||
{
|
||||
while (m_String[Pos] != '\n' && Pos < sizeof(m_String) && m_String[Pos]) // find next \n or \0
|
||||
Pos++;
|
||||
|
||||
CopyPos = m_String + LastPos;
|
||||
StrSize = Pos - LastPos + 1;
|
||||
if(m_String[Pos] == '\n')
|
||||
{
|
||||
Pos++; // skip \n
|
||||
LastPos = Pos;
|
||||
}
|
||||
|
||||
if(StrSize <= 0)
|
||||
{
|
||||
dbg_msg("Load", "Savegame: wrong format (couldn't load Switcher)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(StrSize < sizeof(Switcher))
|
||||
{
|
||||
str_copy(Switcher, CopyPos, StrSize);
|
||||
int Num = sscanf(Switcher, "%d\t%d\t%d", &(m_Switchers[n].m_Status), &(m_Switchers[n].m_EndTime), &(m_Switchers[n].m_Type));
|
||||
if(Num != 3)
|
||||
{
|
||||
dbg_msg("Load", "failed to load Switcher");
|
||||
char aBuf[32];
|
||||
str_format(aBuf, sizeof(aBuf), "loaded %d vars", Num-1);
|
||||
dbg_msg("Load", aBuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("Load", "Savegame: wrong format (couldn't load Switcher, too big)");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
117
src/game/server/save.h
Normal file
117
src/game/server/save.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
#ifndef SAVE_H
|
||||
#define SAVE_H
|
||||
|
||||
#include "./entities/character.h"
|
||||
#include <game/server/gamecontroller.h>
|
||||
|
||||
class CSaveTee
|
||||
{
|
||||
public:
|
||||
CSaveTee();
|
||||
~CSaveTee();
|
||||
void save(CCharacter* pchr);
|
||||
void load(CCharacter* pchr, int Team);
|
||||
char* GetString();
|
||||
int LoadString(char* String);
|
||||
vec2 GetPos() { return m_Pos; }
|
||||
char* GetName() { return m_name; }
|
||||
|
||||
private:
|
||||
|
||||
char m_String [2048];
|
||||
char m_name [16];
|
||||
|
||||
int m_Alive;
|
||||
int m_Paused;
|
||||
int m_NeededFaketuning;
|
||||
|
||||
// Teamstuff
|
||||
int m_TeeFinished;
|
||||
int m_IsSolo;
|
||||
|
||||
struct WeaponStat
|
||||
{
|
||||
int m_AmmoRegenStart;
|
||||
int m_Ammo;
|
||||
int m_Ammocost;
|
||||
int m_Got;
|
||||
|
||||
} m_aWeapons[NUM_WEAPONS];
|
||||
|
||||
int m_LastWeapon;
|
||||
int m_QueuedWeapon;
|
||||
|
||||
int m_SuperJump;
|
||||
int m_Jetpack;
|
||||
int m_NinjaJetpack;
|
||||
int m_FreezeTime;
|
||||
int m_FreezeTick;
|
||||
int m_DeepFreeze;
|
||||
int m_EndlessHook;
|
||||
int m_DDRaceState;
|
||||
|
||||
int m_Hit;
|
||||
int m_Collision;
|
||||
int m_TuneZone;
|
||||
int m_TuneZoneOld;
|
||||
int m_Hook;
|
||||
int m_Time;
|
||||
vec2 m_Pos;
|
||||
vec2 m_PrevPos;
|
||||
int m_TeleCheckpoint;
|
||||
int m_LastPenalty;
|
||||
|
||||
int m_CpTime;
|
||||
int m_CpActive;
|
||||
int m_CpLastBroadcast;
|
||||
float m_CpCurrent[25];
|
||||
|
||||
// Core
|
||||
vec2 m_CorePos;
|
||||
vec2 m_Vel;
|
||||
int m_ActiveWeapon;
|
||||
int m_Jumped;
|
||||
int m_JumpedTotal;
|
||||
int m_Jumps;
|
||||
vec2 m_HookPos;
|
||||
vec2 m_HookDir;
|
||||
vec2 m_HookTeleBase;
|
||||
int m_HookTick;
|
||||
int m_HookState;
|
||||
};
|
||||
|
||||
class CSaveTeam
|
||||
{
|
||||
public:
|
||||
CSaveTeam(IGameController* Controller);
|
||||
~CSaveTeam();
|
||||
char* GetString();
|
||||
int GetMembersCount() {return m_MembersCount;}
|
||||
int LoadString(const char* String);
|
||||
int save(int Team);
|
||||
int load(int Team);
|
||||
CSaveTee* SavedTees;
|
||||
|
||||
private:
|
||||
int MatchPlayer(char name[16]);
|
||||
CCharacter* MatchCharacter(char name[16], int SaveID);
|
||||
|
||||
IGameController* m_pController;
|
||||
|
||||
char m_String[65536];
|
||||
|
||||
struct SSimpleSwitchers
|
||||
{
|
||||
int m_Status;
|
||||
int m_EndTime;
|
||||
int m_Type;
|
||||
};
|
||||
SSimpleSwitchers* m_Switchers;
|
||||
|
||||
int m_TeamState;
|
||||
int m_MembersCount;
|
||||
int m_NumSwitchers;
|
||||
int m_TeamLocked;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -60,6 +60,9 @@ public:
|
|||
virtual void ShowPoints(int ClientID, const char* pName, bool Search=false) = 0;
|
||||
|
||||
virtual void RandomUnfinishedMap(int ClientID) = 0;
|
||||
|
||||
virtual void SaveTeam(int Team, const char* Code, int ClientID) = 0;
|
||||
virtual void LoadTeam(const char* Code, int ClientID) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -327,3 +327,17 @@ void CFileScore::RandomUnfinishedMap(int ClientID)
|
|||
str_format(aBuf, sizeof(aBuf), "Random unfinished map not supported in file based servers");
|
||||
GameServer()->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
|
||||
void CFileScore::SaveTeam(int Team, const char* Code, int ClientID)
|
||||
{
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "Save-function not supported in file based servers");
|
||||
GameServer()->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
|
||||
void CFileScore::LoadTeam(const char* Code, int ClientID)
|
||||
{
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "Save-function not supported in file based servers");
|
||||
GameServer()->SendChatTarget(ClientID, aBuf);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ public:
|
|||
virtual void ShowTopPoints(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut);
|
||||
virtual void ShowPoints(int ClientID, const char* pName, bool Search);
|
||||
virtual void RandomUnfinishedMap(int ClientID);
|
||||
virtual void SaveTeam(int Team, const char* Code, int ClientID);
|
||||
virtual void LoadTeam(const char* Code, int ClientID);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../gamemodes/DDRace.h"
|
||||
#include "sql_score.h"
|
||||
#include <engine/shared/console.h>
|
||||
#include "../save.h"
|
||||
|
||||
static LOCK gs_SqlLock = 0;
|
||||
|
||||
|
@ -170,6 +171,9 @@ void CSqlScore::Init()
|
|||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_maps (Map VARCHAR(128) BINARY NOT NULL, Server VARCHAR(32) BINARY NOT NULL, Points INT DEFAULT 0, UNIQUE KEY Map (Map)) CHARACTER SET utf8 ;", m_pPrefix);
|
||||
m_pStatement->execute(aBuf);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_saves (Savegame TEXT CHARACTER SET utf8 BINARY NOT NULL, Map VARCHAR(128) BINARY NOT NULL, Code VARCHAR(128) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY (Map, Code)) CHARACTER SET utf8 ;", m_pPrefix);
|
||||
m_pStatement->execute(aBuf);
|
||||
|
||||
dbg_msg("SQL", "Tables were created successfully");
|
||||
|
||||
// get the best time
|
||||
|
@ -1183,12 +1187,12 @@ void CSqlScore::FuzzyString(char *pString)
|
|||
}
|
||||
|
||||
// anti SQL injection
|
||||
void CSqlScore::ClearString(char *pString)
|
||||
void CSqlScore::ClearString(char *pString, int size)
|
||||
{
|
||||
char newString[32*2-1];
|
||||
char newString[size*2-1];
|
||||
int pos = 0;
|
||||
|
||||
for(int i=0;i<32;i++)
|
||||
for(int i=0;i<size;i++)
|
||||
{
|
||||
if(pString[i] == '\\')
|
||||
{
|
||||
|
@ -1500,4 +1504,237 @@ void CSqlScore::RandomUnfinishedMap(int ClientID)
|
|||
#endif
|
||||
}
|
||||
|
||||
void CSqlScore::SaveTeam(int Team, const char* Code, int ClientID)
|
||||
{
|
||||
CSqlTeamSave *Tmp = new CSqlTeamSave();
|
||||
Tmp->m_Team = Team;
|
||||
Tmp->m_ClientID = ClientID;
|
||||
str_copy(Tmp->m_Code, Code, 32);
|
||||
Tmp->m_pSqlData = this;
|
||||
|
||||
void *SaveThread = thread_create(SaveTeamThread, Tmp);
|
||||
#if defined(CONF_FAMILY_UNIX)
|
||||
pthread_detach((pthread_t)SaveThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSqlScore::SaveTeamThread(void *pUser)
|
||||
{
|
||||
CSaveTeam* SavedTeam = 0;
|
||||
CSqlTeamSave *pData = (CSqlTeamSave *)pUser;
|
||||
|
||||
|
||||
char TeamString[65536];
|
||||
int Team = pData->m_Team;
|
||||
char OriginalCode[32];
|
||||
str_copy(OriginalCode, pData->m_Code, sizeof(OriginalCode));
|
||||
pData->m_pSqlData->ClearString(pData->m_Code, sizeof(pData->m_Code));
|
||||
char Map[128];
|
||||
str_copy(Map, g_Config.m_SvMap, 128);
|
||||
pData->m_pSqlData->ClearString(Map, sizeof(Map));
|
||||
|
||||
int Num = -1;
|
||||
|
||||
if(Team > 0 && Team < 64 && ((CGameControllerDDRace*)(pData->m_pSqlData->GameServer()->m_pController))->m_Teams.Count(Team) > 0)
|
||||
{
|
||||
SavedTeam = new CSaveTeam(pData->m_pSqlData->GameServer()->m_pController);
|
||||
Num = SavedTeam->save(Team);
|
||||
switch (Num)
|
||||
{
|
||||
case 1:
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "You have to be in a Team (from 1-63)");
|
||||
case 2:
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "Could not find your Team");
|
||||
case 3:
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "Unable to find all Characters");
|
||||
default:
|
||||
;
|
||||
}
|
||||
str_copy(TeamString, SavedTeam->GetString(), sizeof(TeamString));
|
||||
pData->m_pSqlData->ClearString(TeamString, sizeof(TeamString));
|
||||
}
|
||||
else
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "You have to be in a Team (from 1-63)");
|
||||
|
||||
lock_wait(gs_SqlLock);
|
||||
// Connect to database
|
||||
if(!Num && pData->m_pSqlData->Connect())
|
||||
{
|
||||
try
|
||||
{
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "select Savegame from %s_saves where Code = '%s' and Map = '%s';", pData->m_pSqlData->m_pPrefix, pData->m_Code, Map);
|
||||
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
|
||||
|
||||
if (pData->m_pSqlData->m_pResults->rowsCount() == 0)
|
||||
{
|
||||
// delete results and statement
|
||||
delete pData->m_pSqlData->m_pResults;
|
||||
|
||||
char aBuf[65536];
|
||||
str_format(aBuf, sizeof(aBuf), "INSERT IGNORE INTO %s_saves(Savegame, Map, Code, Timestamp) VALUES ('%s', '%s', '%s', CURRENT_TIMESTAMP())", pData->m_pSqlData->m_pPrefix, TeamString, Map, pData->m_Code);
|
||||
pData->m_pSqlData->m_pStatement->execute(aBuf);
|
||||
|
||||
char aBuf2[256];
|
||||
str_format(aBuf2, sizeof(aBuf2), "Team successfully saved. Use '/load %s' to continue", OriginalCode);
|
||||
pData->m_pSqlData->GameServer()->SendChatTeam(Team, aBuf2);
|
||||
((CGameControllerDDRace*)(pData->m_pSqlData->GameServer()->m_pController))->m_Teams.KillTeam(Team);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("SQL", "ERROR: This save-code already exists");
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "This save-code already exists");
|
||||
}
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
{
|
||||
char aBuf2[256];
|
||||
str_format(aBuf2, sizeof(aBuf2), "MySQL Error: %s", e.what());
|
||||
dbg_msg("SQL", aBuf2);
|
||||
dbg_msg("SQL", "ERROR: Could not save the team");
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "MySQL Error: Could not save the team");
|
||||
}
|
||||
|
||||
// disconnect from database
|
||||
pData->m_pSqlData->Disconnect();
|
||||
}
|
||||
else if(!Num)
|
||||
{
|
||||
dbg_msg("SQL", "connection failed");
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "ERROR: Unable to connect to SQL-Server");
|
||||
}
|
||||
|
||||
delete pData;
|
||||
if(SavedTeam)
|
||||
delete SavedTeam;
|
||||
|
||||
lock_release(gs_SqlLock);
|
||||
}
|
||||
|
||||
void CSqlScore::LoadTeam(const char* Code, int ClientID)
|
||||
{
|
||||
CSqlTeamLoad *Tmp = new CSqlTeamLoad();
|
||||
str_copy(Tmp->m_Code, Code, 32);
|
||||
Tmp->m_ClientID = ClientID;
|
||||
Tmp->m_pSqlData = this;
|
||||
|
||||
void *LoadThread = thread_create(LoadTeamThread, Tmp);
|
||||
#if defined(CONF_FAMILY_UNIX)
|
||||
pthread_detach((pthread_t)LoadThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSqlScore::LoadTeamThread(void *pUser)
|
||||
{
|
||||
CSaveTeam* SavedTeam;
|
||||
CSqlTeamLoad *pData = (CSqlTeamLoad *)pUser;
|
||||
|
||||
SavedTeam = new CSaveTeam(pData->m_pSqlData->GameServer()->m_pController);
|
||||
|
||||
pData->m_pSqlData->ClearString(pData->m_Code, sizeof(pData->m_Code));
|
||||
char Map[128];
|
||||
str_copy(Map, g_Config.m_SvMap, 128);
|
||||
pData->m_pSqlData->ClearString(Map, sizeof(Map));
|
||||
int Num;
|
||||
|
||||
lock_wait(gs_SqlLock);
|
||||
// Connect to database
|
||||
if(pData->m_pSqlData->Connect())
|
||||
{
|
||||
try
|
||||
{
|
||||
char aBuf[768];
|
||||
str_format(aBuf, sizeof(aBuf), "select Savegame from %s_saves where Code = '%s' and Map = '%s';", pData->m_pSqlData->m_pPrefix, pData->m_Code, Map);
|
||||
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
|
||||
|
||||
if (pData->m_pSqlData->m_pResults->rowsCount() > 0)
|
||||
{
|
||||
pData->m_pSqlData->m_pResults->first();
|
||||
Num = SavedTeam->LoadString(pData->m_pSqlData->m_pResults->getString("Savegame").c_str());
|
||||
|
||||
if(Num)
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "Unable to load Savegame: datas corrupted");
|
||||
else
|
||||
{
|
||||
|
||||
bool found = false;
|
||||
for (int i = 0; i < SavedTeam->GetMembersCount(); i++)
|
||||
{
|
||||
if(str_comp(SavedTeam->SavedTees[i].GetName(), pData->m_pSqlData->Server()->ClientName(pData->m_ClientID)) == 0)
|
||||
{ found = true; break; }
|
||||
}
|
||||
if (!found)
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "You don't belong to this Team");
|
||||
else
|
||||
{
|
||||
|
||||
int n;
|
||||
for(n = 1; n<64; n++)
|
||||
{
|
||||
if(((CGameControllerDDRace*)(pData->m_pSqlData->GameServer()->m_pController))->m_Teams.Count(n) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(((CGameControllerDDRace*)(pData->m_pSqlData->GameServer()->m_pController))->m_Teams.Count(n) > 0)
|
||||
{
|
||||
n = ((CGameControllerDDRace*)(pData->m_pSqlData->GameServer()->m_pController))->m_Teams.m_Core.Team(pData->m_ClientID); // if all Teams are full your the only one in your team
|
||||
}
|
||||
|
||||
Num = SavedTeam->load(n);
|
||||
|
||||
if(Num == 1)
|
||||
{
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "You have to be in a Team (from 1-63)");
|
||||
}
|
||||
else if(Num >= 10 && Num < 100)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Unable to find player: '%s'", SavedTeam->SavedTees[Num-10].GetName());
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
|
||||
}
|
||||
else if(Num >= 100)
|
||||
{
|
||||
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->SavedTees[Num-100].GetName());
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
pData->m_pSqlData->GameServer()->SendChatTeam(n, "Loading successfully done");
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "DELETE from %s_saves where Code='%s' and Map='%s';", pData->m_pSqlData->m_pPrefix, pData->m_Code, Map);
|
||||
pData->m_pSqlData->m_pStatement->execute(aBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "No such savegame for this map");
|
||||
// delete results and statement
|
||||
delete pData->m_pSqlData->m_pResults;
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
{
|
||||
char aBuf2[256];
|
||||
str_format(aBuf2, sizeof(aBuf2), "MySQL Error: %s", e.what());
|
||||
dbg_msg("SQL", aBuf2);
|
||||
dbg_msg("SQL", "ERROR: Could not load the team");
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "MySQL Error: Could not load the team");
|
||||
}
|
||||
|
||||
// disconnect from database
|
||||
pData->m_pSqlData->Disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_msg("SQL", "connection failed");
|
||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "ERROR: Unable to connect to SQL-Server");
|
||||
}
|
||||
|
||||
delete pData;
|
||||
delete SavedTeam;
|
||||
|
||||
lock_release(gs_SqlLock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -53,6 +53,8 @@ class CSqlScore: public IScore
|
|||
static void ShowPointsThread(void *pUser);
|
||||
static void ShowTopPointsThread(void *pUser);
|
||||
static void RandomUnfinishedMapThread(void *pUser);
|
||||
static void SaveTeamThread(void *pUser);
|
||||
static void LoadTeamThread(void *pUser);
|
||||
|
||||
void Init();
|
||||
|
||||
|
@ -61,7 +63,7 @@ class CSqlScore: public IScore
|
|||
|
||||
void FuzzyString(char *pString);
|
||||
// anti SQL injection
|
||||
void ClearString(char *pString);
|
||||
void ClearString(char *pString, int size = 32);
|
||||
|
||||
void NormalizeMapname(char *pString);
|
||||
|
||||
|
@ -88,6 +90,8 @@ public:
|
|||
virtual void ShowTopPoints(IConsole::IResult *pResult, int ClientID,
|
||||
void *pUserData, int Debut = 1);
|
||||
virtual void RandomUnfinishedMap(int ClientID);
|
||||
virtual void SaveTeam(int Team, const char* Code, int ClientID);
|
||||
virtual void LoadTeam(const char* Code, int ClientID);
|
||||
static void agoTimeToString(int agoTime, char agoString[]);
|
||||
};
|
||||
|
||||
|
@ -133,4 +137,19 @@ struct CSqlTeamScoreData
|
|||
char m_aRequestingPlayer[MAX_NAME_LENGTH];
|
||||
};
|
||||
|
||||
struct CSqlTeamSave
|
||||
{
|
||||
int m_Team;
|
||||
int m_ClientID;
|
||||
char m_Code[128];
|
||||
CSqlScore *m_pSqlData;
|
||||
};
|
||||
|
||||
struct CSqlTeamLoad
|
||||
{
|
||||
char m_Code[128];
|
||||
int m_ClientID;
|
||||
CSqlScore *m_pSqlData;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -595,3 +595,12 @@ void CGameTeams::SetTeamLock(int Team, bool Lock)
|
|||
{
|
||||
m_TeamLocked[Team] = Lock;
|
||||
}
|
||||
|
||||
void CGameTeams::KillTeam(int Team)
|
||||
{
|
||||
for (int i = 0; i < MAX_CLIENTS; i++)
|
||||
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
||||
GameServer()->m_apPlayers[i]->KillCharacter(-2);
|
||||
|
||||
ChangeTeamState(Team, CGameTeams::TEAMSTATE_OPEN);
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
void SetCpActive(CPlayer* Player, int CpActive);
|
||||
void OnTeamFinish(CPlayer** Players, unsigned int Size);
|
||||
void OnFinish(CPlayer* Player);
|
||||
void KillTeam(int Team);
|
||||
bool TeeFinished(int ClientID)
|
||||
{
|
||||
return m_TeeFinished[ClientID];
|
||||
|
@ -97,6 +98,11 @@ public:
|
|||
return m_TeamLocked[Team];
|
||||
}
|
||||
;
|
||||
void SetFinished(int ClientID, bool finished)
|
||||
{
|
||||
m_TeeFinished[ClientID] = finished;
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue