From 51c6af13039240c1daecf36fab73784fd4b17c07 Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Mon, 23 Aug 2010 23:40:23 +0200 Subject: [PATCH 1/8] SvShotgunBulletSound also added protection to shotgun stucks, needs to be tested when a random crazy shotgun bullet gets stuck loaded the score file before saving to avoid corruption added freeze and unfreeze in rcon added protection in some rcon commands Signed-off-by: GreYFoXGTi --- src/engine/server/server.cpp | 4 +- src/engine/shared/config_variables.h | 1 + src/game/server/entities/character.cpp | 22 +++-- src/game/server/entities/pickup.cpp | 13 ++- src/game/server/entities/projectile.cpp | 44 ++++++++- src/game/server/entities/projectile.h | 5 + src/game/server/gamecontext.cpp | 116 ++++++++++++++++++------ src/game/server/gamecontext.h | 2 + src/game/server/gamecontroller.cpp | 2 +- src/game/server/player.h | 2 +- src/game/server/score.cpp | 3 +- 11 files changed, 166 insertions(+), 48 deletions(-) diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 9403baf90..28a7b07c5 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -933,14 +933,14 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) } if(level != -1) { - char buf[128]="Authentication successful. Remote console access granted, with level=%d"; + char buf[128]="Authentication successful. Remote console access grantedfor cid=%d with level=%d"; CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); Msg.AddInt(1); SendMsgEx(&Msg, MSGFLAG_VITAL, ClientId, true); m_aClients[ClientId].m_Authed = level; GameServer()->OnSetAuthed(ClientId, m_aClients[ClientId].m_Authed); - str_format(buf,sizeof(buf),buf,level); + str_format(buf,sizeof(buf),buf,ClientId,level); SendRconLine(ClientId, buf); dbg_msg("server", "ClientId=%d authed with Level=%d", ClientId, level); m_aClients[ClientId].m_PwTries = 0; diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index ea347f15c..aafa9bb7c 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -8,6 +8,7 @@ //=============================== /* DDRace */ //MACRO_CONFIG_STR(SvEntities, sv_entities, 64, "Latest", CFGFLAG_SERVER, "The type of entities used") still need to think of a way +MACRO_CONFIG_INT(SvShotgunBulletSound, sv_shotgun_bullet_sound, 1, 0, 1, CFGFLAG_SERVER, "Annoying Shotgun sound on/off") MACRO_CONFIG_INT(SvEndlessSuperHook, sv_endless_super_hook, 0, 0, 1, CFGFLAG_SERVER, "Endless hook for super players on/off") MACRO_CONFIG_INT(SvEmotionalTees, sv_emotional_tees, 1, 0, 1, CFGFLAG_SERVER, "Emotional Tees on/off") MACRO_CONFIG_INT(SvOldShotgun, sv_old_shotgun, 0, 0, 1, CFGFLAG_SERVER, "Makes Shotgun laser pull towards the shooter, rather than the last bounce origin") diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 437e245c2..5ab95e402 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -61,7 +61,7 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos) m_ActiveWeapon = WEAPON_GUN; m_LastWeapon = WEAPON_HAMMER; m_QueuedWeapon = -1; - + m_pPlayer = pPlayer; m_Pos = Pos; m_OlderPos = Pos; @@ -79,7 +79,8 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos) GameServer()->m_World.InsertEntity(this); m_Alive = true; - + dbg_msg("m_RconFreeze","%d",m_pPlayer->m_RconFreeze); + if(m_pPlayer->m_RconFreeze) Freeze(-1); GameServer()->m_pController->OnCharacterSpawn(this); return true; @@ -559,19 +560,24 @@ void CCharacter::Tick() m_pPlayer->m_ForceBalanced = false; } - m_Armor=10-(m_FreezeTime/15); + m_Armor=(m_FreezeTime != -1)?10-(m_FreezeTime/15):0; if(m_Input.m_Direction != 0 || m_Input.m_Jump != 0) m_LastMove = Server()->Tick(); - if(m_FreezeTime > 0) { - if (m_FreezeTime % Server()->TickSpeed() == 0) + if(m_FreezeTime > 0 || m_FreezeTime == -1) + { + if (m_FreezeTime % Server()->TickSpeed() == 0 || m_FreezeTime == -1) { GameServer()->CreateDamageInd(m_Pos, 0, m_FreezeTime / Server()->TickSpeed()); } - m_FreezeTime--; + (m_FreezeTime != -1)?m_FreezeTime--:0; m_Input.m_Direction = 0; m_Input.m_Jump = 0; m_Input.m_Hook = 0; + m_Ninja.m_ActivationTick = Server()->Tick(); + m_aWeapons[WEAPON_NINJA].m_Got=true; + m_aWeapons[WEAPON_NINJA].m_Ammo =0; + m_ActiveWeapon=WEAPON_NINJA; //m_Input.m_Fire = 0; if (m_FreezeTime == 1) { UnFreeze(); @@ -944,7 +950,7 @@ void CCharacter::TickDefered() bool CCharacter::Freeze(int Time) { - if (Time <= 1 || m_Super) + if ((Time <= 1 || m_Super || m_FreezeTime == -1) && Time != -1) return false; if (m_FreezeTick < Server()->Tick() - Server()->TickSpeed()) { @@ -964,7 +970,7 @@ bool CCharacter::Freeze(int Time) bool CCharacter::Freeze() { int Time = Server()->TickSpeed()*3; - if (Time <= 1 || m_Super) + if (Time <= 1 || m_Super || m_FreezeTime == -1) return false; if (m_FreezeTick < Server()->Tick() - Server()->TickSpeed()) { diff --git a/src/game/server/entities/pickup.cpp b/src/game/server/entities/pickup.cpp index 608e8e06d..9d34ac131 100644 --- a/src/game/server/entities/pickup.cpp +++ b/src/game/server/entities/pickup.cpp @@ -72,9 +72,12 @@ void CPickup::Tick() { if (pChr->m_aWeapons[i].m_Got) { - pChr->m_aWeapons[i].m_Got = false; - pChr->m_aWeapons[i].m_Ammo = 0; - sound = true; + if(!(pChr->m_FreezeTime && i == WEAPON_NINJA)) + { + pChr->m_aWeapons[i].m_Got = false; + pChr->m_aWeapons[i].m_Ammo = 0; + sound = true; + } } if(pChr->m_FreezeTime) { @@ -90,7 +93,7 @@ void CPickup::Tick() pChr->m_LastWeapon = WEAPON_GUN; GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR); } - pChr->m_ActiveWeapon = WEAPON_HAMMER; + if(!pChr->m_FreezeTime) pChr->m_ActiveWeapon = WEAPON_HAMMER; break; case POWERUP_WEAPON: @@ -117,7 +120,7 @@ void CPickup::Tick() case POWERUP_NINJA: { // activate ninja on target player - pChr->GiveNinja(); + if(!pChr->m_FreezeTime) pChr->GiveNinja(); //RespawnTime = g_pData->m_aPickups[m_Type].m_Respawntime; break; diff --git a/src/game/server/entities/projectile.cpp b/src/game/server/entities/projectile.cpp index b2fe5a5ce..9fb2e1a58 100644 --- a/src/game/server/entities/projectile.cpp +++ b/src/game/server/entities/projectile.cpp @@ -3,8 +3,18 @@ #include #include "projectile.h" -CProjectile::CProjectile(CGameWorld *pGameWorld, int Type, int Owner, vec2 Pos, vec2 Dir, int Span, - bool Freeze, bool Explosive, float Force, int SoundImpact, int Weapon) +CProjectile::CProjectile( + CGameWorld *pGameWorld, + int Type, + int Owner, + vec2 Pos, + vec2 Dir, + int Span, + bool Freeze, + bool Explosive, + float Force, + int SoundImpact, + int Weapon) : CEntity(pGameWorld, NETOBJTYPE_PROJECTILE) { m_Type = Type; @@ -19,6 +29,11 @@ CProjectile::CProjectile(CGameWorld *pGameWorld, int Type, int Owner, vec2 Pos, m_Weapon = Weapon; m_StartTick = Server()->Tick(); m_Explosive = Explosive; + m_BouncePos=vec2(0,0); + m_ReBouncePos=vec2(0,0); + m_AvgPos=vec2(0,0); + m_LastBounce=vec2(0,0); + m_PrevLastBounce=vec2(0,0); GameWorld()->InsertEntity(this); } @@ -55,7 +70,8 @@ vec2 CProjectile::GetPos(float Time) return CalcPos(m_Pos, m_Direction, Curvature, Speed, Time); } -void CProjectile::SetBouncing(int Value) { +void CProjectile::SetBouncing(int Value) +{ m_Bouncing = Value; } @@ -96,9 +112,27 @@ void CProjectile::Tick() m_StartTick = Server()->Tick(); m_Pos = NewPos; if (m_Bouncing == 1) + { m_Direction.x = -m_Direction.x; + m_LastBounce = m_Pos; + if(!m_BouncePos.x) + m_BouncePos=m_Pos; + else if (!m_ReBouncePos.x) + m_ReBouncePos=m_Pos; + else if(!m_AvgPos.x) + m_AvgPos = vec2((m_BouncePos.x+m_ReBouncePos.x)/2,(m_BouncePos.y+m_ReBouncePos.y)/2); + } else if (m_Bouncing == 2) + { + m_LastBounce = m_Pos; m_Direction.y =- m_Direction.y; + if(!m_BouncePos.y) + m_BouncePos=m_Pos; + else if (!m_ReBouncePos.y) + m_ReBouncePos=m_Pos; + else if(!m_AvgPos.y) + m_AvgPos = vec2((m_BouncePos.x+m_ReBouncePos.x)/2,(m_BouncePos.y+m_ReBouncePos.y)/2); + } m_Pos += m_Direction; } else if (m_Weapon == WEAPON_GUN) @@ -114,6 +148,10 @@ void CProjectile::Tick() { GameServer()->m_World.DestroyEntity(this); } + + if((!(m_PrevLastBounce == m_BouncePos && m_LastBounce == m_ReBouncePos) && !(m_LastBounce == m_BouncePos && m_PrevLastBounce == m_ReBouncePos))&&m_AvgPos.x) + m_Pos=m_AvgPos; + m_PrevLastBounce=m_LastBounce; } void CProjectile::FillInfo(CNetObj_Projectile *pProj) diff --git a/src/game/server/entities/projectile.h b/src/game/server/entities/projectile.h index 149122467..e2ccea953 100644 --- a/src/game/server/entities/projectile.h +++ b/src/game/server/entities/projectile.h @@ -29,6 +29,11 @@ private: int m_Bouncing; bool m_Freeze; bool m_Collised; + vec2 m_AvgPos; + vec2 m_BouncePos; + vec2 m_ReBouncePos; + vec2 m_LastBounce; + vec2 m_PrevLastBounce; }; #endif diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 51748fdfa..9cc6a479e 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -1350,7 +1350,7 @@ void CGameContext::ConSetlvl(IConsole::IResult *pResult, void *pUserData, int c int cid1 = clamp(pResult->GetInteger(0), 0, (int)MAX_CLIENTS-1); int level = clamp(pResult->GetInteger(1), 0, 3); - if (pSelf->m_apPlayers[cid1] && (pSelf->m_apPlayers[cid1]->m_Authed > level) && (compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1]))) + if (pSelf->m_apPlayers[cid1] && (pSelf->m_apPlayers[cid1]->m_Authed > level) && (compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1]) || cid == cid1)) { pSelf->m_apPlayers[cid1]->m_Authed = level; } @@ -1388,10 +1388,14 @@ void CGameContext::ConNinja(IConsole::IResult *pResult, void *pUserData, int cid if(!pSelf->CheatsAvailable(cid)) return; int cid1 = clamp(pResult->GetInteger(0), 0, (int)MAX_CLIENTS-1); CCharacter* chr = pSelf->GetPlayerChar(cid1); - if(chr) { - chr->GiveNinja(); - if(!g_Config.m_SvCheatTime) - chr->m_RaceState = RACE_CHEAT; + if(chr) + { + if (pSelf->m_apPlayers[cid1] && compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1])) + { + chr->GiveNinja(); + if(!g_Config.m_SvCheatTime) + chr->m_RaceState = RACE_CHEAT; + } } } @@ -1414,11 +1418,14 @@ void CGameContext::ConHammer(IConsole::IResult *pResult, void *pUserData, int ci } else { - chr->m_HammerType = type; - if(!g_Config.m_SvCheatTime) - chr->m_RaceState = RACE_CHEAT; - str_format(buf, sizeof(buf), "Hammer of cid=%d setted to %d",cid1,type); - serv->SendRconLine(cid1, buf); + if (pSelf->m_apPlayers[cid1] && compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1])) + { + chr->m_HammerType = type; + if(!g_Config.m_SvCheatTime) + chr->m_RaceState = RACE_CHEAT; + str_format(buf, sizeof(buf), "Hammer of cid=%d setted to %d",cid1,type); + serv->SendRconLine(cid1, buf); + } } } @@ -1458,6 +1465,7 @@ void CGameContext::ConSuper(IConsole::IResult *pResult, void *pUserData, int cid if(chr) { chr->m_Super = true; + chr->UnFreeze(); if(!g_Config.m_SvCheatTime) chr->m_RaceState = RACE_CHEAT; } @@ -1489,6 +1497,7 @@ void CGameContext::ConSuperMe(IConsole::IResult *pResult, void *pUserData, int c if(chr) { chr->m_Super = true; + chr->UnFreeze(); if(!g_Config.m_SvCheatTime) chr->m_RaceState = RACE_CHEAT; } @@ -1573,9 +1582,12 @@ void CGameContext::ConTimerStop(IConsole::IResult *pResult, void *pUserData, int CCharacter* chr = pSelf->GetPlayerChar(cid1); if (!chr) return; - chr->m_RaceState=RACE_CHEAT; - str_format(buf, sizeof(buf), "Cid=%d Hasn't time now (Timer Stopped)",cid1); - serv->SendRconLine(cid1, buf); + if (pSelf->m_apPlayers[cid1] && compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1])) + { + chr->m_RaceState=RACE_CHEAT; + str_format(buf, sizeof(buf), "Cid=%d Hasn't time now (Timer Stopped)",cid1); + serv->SendRconLine(cid1, buf); + } } else { @@ -1596,9 +1608,12 @@ void CGameContext::ConTimerStart(IConsole::IResult *pResult, void *pUserData, in CCharacter* chr = pSelf->GetPlayerChar(cid1); if (!chr) return; - chr->m_RaceState = RACE_STARTED; - str_format(buf, sizeof(buf), "Cid=%d Has time now (Timer Started)",cid1); - serv->SendRconLine(cid1, buf); + if (pSelf->m_apPlayers[cid1] && compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1])) + { + chr->m_RaceState = RACE_STARTED; + str_format(buf, sizeof(buf), "Cid=%d Has time now (Timer Started)",cid1); + serv->SendRconLine(cid1, buf); + } } else { @@ -1618,12 +1633,15 @@ void CGameContext::ConTimerZero(IConsole::IResult *pResult, void *pUserData, int CCharacter* chr = pSelf->GetPlayerChar(cid1); if (!chr) return; - chr->m_StartTime = pSelf->Server()->Tick(); - chr->m_RefreshTime = pSelf->Server()->Tick(); - chr->m_RaceState=RACE_CHEAT; - str_format(buf, sizeof(buf), "Cid=%d time has been reset & stopped.",cid1); - CServer* serv = (CServer*)pSelf->Server(); - serv->SendRconLine(cid1, buf); + if (pSelf->m_apPlayers[cid1] && compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1])) + { + chr->m_StartTime = pSelf->Server()->Tick(); + chr->m_RefreshTime = pSelf->Server()->Tick(); + chr->m_RaceState=RACE_CHEAT; + str_format(buf, sizeof(buf), "Cid=%d time has been reset & stopped.",cid1); + CServer* serv = (CServer*)pSelf->Server(); + serv->SendRconLine(cid1, buf); + } } @@ -1638,10 +1656,53 @@ void CGameContext::ConTimerReStart(IConsole::IResult *pResult, void *pUserData, CCharacter* chr = pSelf->GetPlayerChar(cid1); if (!chr) return; - chr->m_StartTime = pSelf->Server()->Tick(); - chr->m_RefreshTime = pSelf->Server()->Tick(); - chr->m_RaceState=RACE_STARTED; - str_format(buf, sizeof(buf), "Cid=%d time has been reset & stopped.",cid1); + if (pSelf->m_apPlayers[cid1] && compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1])) + { + chr->m_StartTime = pSelf->Server()->Tick(); + chr->m_RefreshTime = pSelf->Server()->Tick(); + chr->m_RaceState=RACE_STARTED; + str_format(buf, sizeof(buf), "Cid=%d time has been reset & stopped.",cid1); + CServer* serv = (CServer*)pSelf->Server(); + serv->SendRconLine(cid1, buf); + } + +} + +void CGameContext::ConFreeze(IConsole::IResult *pResult, void *pUserData, int cid) +{ + CGameContext *pSelf = (CGameContext *)pUserData; + //if(!pSelf->CheatsAvailable(cid)) return; + char buf[128]; + int time=-1; + int cid1 = clamp(pResult->GetInteger(0), 0, (int)MAX_CLIENTS-1); + if(pResult->NumArguments()>1) + time = clamp(pResult->GetInteger(1), -1, 29999); + CCharacter* chr = pSelf->GetPlayerChar(cid1); + if (!chr) + return; + if (pSelf->m_apPlayers[cid1] && compare_players(pSelf->m_apPlayers[cid],pSelf->m_apPlayers[cid1])) + { + chr->Freeze(((time!=0&&time!=-1)?(pSelf->Server()->TickSpeed()*time):(-1))); + chr->m_pPlayer->m_RconFreeze = true; + str_format(buf, sizeof(buf), "Cid=%d has been Frozen.",cid1); + CServer* serv = (CServer*)pSelf->Server(); + serv->SendRconLine(cid1, buf); + } + +} + +void CGameContext::ConUnFreeze(IConsole::IResult *pResult, void *pUserData, int cid) +{ + CGameContext *pSelf = (CGameContext *)pUserData; + //if(!pSelf->CheatsAvailable(cid)) return; + char buf[128]; + int cid1 = clamp(pResult->GetInteger(0), 0, (int)MAX_CLIENTS-1); + CCharacter* chr = pSelf->GetPlayerChar(cid1); + if (!chr) + return; + chr->m_FreezeTime=2; + chr->m_pPlayer->m_RconFreeze = false; + str_format(buf, sizeof(buf), "Cid=%d has been UnFreezed.",cid1); CServer* serv = (CServer*)pSelf->Server(); serv->SendRconLine(cid1, buf); @@ -1651,7 +1712,8 @@ void CGameContext::OnConsoleInit() { m_pServer = Kernel()->RequestInterface(); m_pConsole = Kernel()->RequestInterface(); - + Console()->Register("freeze", "i?i", CFGFLAG_SERVER, ConFreeze, this, "Freezes Player i1 for i2 seconds Default Infinity",2); + Console()->Register("unfreeze", "i", CFGFLAG_SERVER, ConUnFreeze, this, "UnFreezes Player i",2); Console()->Register("timerstop", "i", CFGFLAG_SERVER, ConTimerStop, this, "Stops The Timer of Player i",2); Console()->Register("timerstart", "i", CFGFLAG_SERVER, ConTimerStart, this, "Starts The Timer of Player i",2); Console()->Register("timerrestart", "i", CFGFLAG_SERVER, ConTimerReStart, this, "Starts The Timer of Player i with the time of 00:00:00",2); diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 8a84ff7d9..780e76b7c 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -68,6 +68,8 @@ class CGameContext : public IGameServer static void ConPhook(IConsole::IResult *pResult, void *pUserData, int cid); + static void ConFreeze(IConsole::IResult *pResult, void *pUserData, int cid); + static void ConUnFreeze(IConsole::IResult *pResult, void *pUserData, int cid); static void ConTimerStop(IConsole::IResult *pResult, void *pUserData, int cid); static void ConTimerStart(IConsole::IResult *pResult, void *pUserData, int cid); static void ConTimerReStart(IConsole::IResult *pResult, void *pUserData, int cid); diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index 53702c6de..deb9c6e0f 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -179,7 +179,7 @@ bool IGameController::OnEntity(int Index, vec2 Pos, bool Front) true, //Freeze true, //Explosive 0, - SOUND_GRENADE_EXPLODE, + (g_Config.m_SvShotgunBulletSound)?SOUND_GRENADE_EXPLODE:-1, WEAPON_SHOTGUN); bullet->SetBouncing(2 - (i % 2)); diff --git a/src/game/server/player.h b/src/game/server/player.h index a736e38be..64ad17309 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -120,7 +120,7 @@ public: int m_SentAfkWarning; // afk timer's 1st warning after 50% of sv_max_afk_time int m_SentAfkWarning2; // afk timer's 2nd warning after 90% of sv_max_afk_time char m_pAfkMsg[160]; - + bool m_RconFreeze; private: CCharacter *Character; CGameContext *m_pGameServer; diff --git a/src/game/server/score.cpp b/src/game/server/score.cpp index 7c11e4197..617c22668 100644 --- a/src/game/server/score.cpp +++ b/src/game/server/score.cpp @@ -106,6 +106,7 @@ CPlayerScore *CScore::SearchName(const char *name) void CScore::ParsePlayer(const char *name, float score) { + Load(); CPlayerScore *player = SearchName(name); if (player) { @@ -131,7 +132,7 @@ std::list CScore::Top5Draw(int id, int debut) //Thanks nevi //char buf[512]; res.push_back("----------- Top 5 -----------"); - for (std::list::iterator i = top.begin(); i != top.end() && pos <= 5+debut; i++) + for (std::list::iterator i = top.begin(); i != top.end() && pos <= ((debut)?4:5)+debut; i++) { if(i->m_Score < 0) continue; From 8000f91ec70efd522309da223d20086b48161c7f Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Tue, 24 Aug 2010 01:21:35 +0200 Subject: [PATCH 2/8] Fixed The Crazy Shotguns and added dbg message if detected out of bounds Signed-off-by: GreYFoXGTi --- src/game/server/entities/projectile.cpp | 56 ++++++++++++++++++++----- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/src/game/server/entities/projectile.cpp b/src/game/server/entities/projectile.cpp index 9fb2e1a58..974b179be 100644 --- a/src/game/server/entities/projectile.cpp +++ b/src/game/server/entities/projectile.cpp @@ -113,25 +113,60 @@ void CProjectile::Tick() m_Pos = NewPos; if (m_Bouncing == 1) { - m_Direction.x = -m_Direction.x; - m_LastBounce = m_Pos; + m_PrevLastBounce.x = m_LastBounce.x; + m_LastBounce.x = m_Pos.x; if(!m_BouncePos.x) - m_BouncePos=m_Pos; + m_BouncePos.x=m_Pos.x; else if (!m_ReBouncePos.x) - m_ReBouncePos=m_Pos; + m_ReBouncePos.x=m_Pos.x; else if(!m_AvgPos.x) m_AvgPos = vec2((m_BouncePos.x+m_ReBouncePos.x)/2,(m_BouncePos.y+m_ReBouncePos.y)/2); + if (m_AvgPos.x) + if(!((m_PrevLastBounce.x+1 == m_BouncePos.x || m_PrevLastBounce.x-1 == m_BouncePos.x || m_PrevLastBounce.x == m_BouncePos.x) && (m_LastBounce.x == m_ReBouncePos.x || m_LastBounce.x+1 == m_ReBouncePos.x || m_LastBounce.x-1 == m_ReBouncePos.x)) && !((m_LastBounce.x == m_BouncePos.x || m_LastBounce.x+1 == m_BouncePos.x || m_LastBounce.x-1 == m_BouncePos.x) && (m_PrevLastBounce.x+1 == m_ReBouncePos.x || m_PrevLastBounce.x-1 == m_ReBouncePos.x || m_PrevLastBounce.x == m_ReBouncePos.x))) + { + /*int bx=(int)m_BouncePos.x; + int rbx=(int)m_ReBouncePos.x; + int lbx=(int)m_LastBounce.x; + int plbx=(int)m_PrevLastBounce.x; + dbg_msg("m_BouncePos","%d",bx); + dbg_msg("m_ReBouncePos","%d",rbx); + dbg_msg("m_LastBounce","%d",lbx); + dbg_msg("m_PrevLastBounce","%d",plbx); + m_Pos.x=m_AvgPos.x;*/ + dbg_msg("CrazyShotgun","Warning Horizontal Crazy Shotgun Out of bounds"); + /*int x=(int)m_Pos.x; + dbg_msg("RePos","%d",x);*/ + } + m_Direction.x =- m_Direction.x; } else if (m_Bouncing == 2) { - m_LastBounce = m_Pos; - m_Direction.y =- m_Direction.y; + m_PrevLastBounce.y = m_LastBounce.y; + m_LastBounce.y = m_Pos.y; if(!m_BouncePos.y) - m_BouncePos=m_Pos; + m_BouncePos.y=m_Pos.y; else if (!m_ReBouncePos.y) - m_ReBouncePos=m_Pos; + m_ReBouncePos.y=m_Pos.y; else if(!m_AvgPos.y) m_AvgPos = vec2((m_BouncePos.x+m_ReBouncePos.x)/2,(m_BouncePos.y+m_ReBouncePos.y)/2); + m_Direction.y =- m_Direction.y; + if (m_AvgPos.y) + if(!((m_PrevLastBounce.y+1 == m_BouncePos.y || m_PrevLastBounce.y-1 == m_BouncePos.y || m_PrevLastBounce.y == m_BouncePos.y) && (m_LastBounce.y == m_ReBouncePos.y || m_LastBounce.y+1 == m_ReBouncePos.y || m_LastBounce.y-1 == m_ReBouncePos.y)) && !((m_LastBounce.y == m_BouncePos.y || m_LastBounce.y+1 == m_BouncePos.y || m_LastBounce.y-1 == m_BouncePos.y) && (m_PrevLastBounce.y+1 == m_ReBouncePos.y || m_PrevLastBounce.y-1 == m_ReBouncePos.y || m_PrevLastBounce.y == m_ReBouncePos.y))) + { + /*int by=(int)m_BouncePos.y; + int rby=(int)m_ReBouncePos.y; + int lby=(int)m_LastBounce.y; + int plby=(int)m_PrevLastBounce.y; + dbg_msg("m_BouncePos","%d",by); + dbg_msg("m_ReBouncePos","%d",rby); + dbg_msg("m_LastBounce","%d",lby); + dbg_msg("m_PrevLastBounce","%d",plby);*/ + m_Pos=m_AvgPos; + dbg_msg("CrazyShotgun","Warning Vertical Crazy Shotgun Out of bounds"); + /*int y=(int)m_Pos.y; + dbg_msg("RePos","%d",y);*/ + + } } m_Pos += m_Direction; } @@ -149,9 +184,8 @@ void CProjectile::Tick() GameServer()->m_World.DestroyEntity(this); } - if((!(m_PrevLastBounce == m_BouncePos && m_LastBounce == m_ReBouncePos) && !(m_LastBounce == m_BouncePos && m_PrevLastBounce == m_ReBouncePos))&&m_AvgPos.x) - m_Pos=m_AvgPos; - m_PrevLastBounce=m_LastBounce; + + } void CProjectile::FillInfo(CNetObj_Projectile *pProj) From ed575f9b0c0388e860d899082815931e54341541 Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Tue, 24 Aug 2010 03:30:22 +0200 Subject: [PATCH 3/8] Fixed 2x and 1.5x boosters Removed Unused Vars Signed-off-by: GreYFoXGTi --- src/game/server/entities/character.cpp | 20 +++++++++++--------- src/game/server/entities/character.h | 3 ++- src/game/server/player.cpp | 2 -- src/game/server/player.h | 1 - 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 5ab95e402..037c0b642 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -79,7 +79,6 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos) GameServer()->m_World.InsertEntity(this); m_Alive = true; - dbg_msg("m_RconFreeze","%d",m_pPlayer->m_RconFreeze); if(m_pPlayer->m_RconFreeze) Freeze(-1); GameServer()->m_pController->OnCharacterSpawn(this); @@ -729,58 +728,61 @@ void CCharacter::Tick() { if(m_PrevPos.x-m_Pos.x<0) m_Core.m_Vel.x += m_Core.m_Vel.x *-0.5; - else + else if(m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2) m_Core.m_Vel.x += m_Core.m_Vel.x*0.5; } if (TileIndex1 == TILE_BOOST_R || TileIndex2 == TILE_BOOST_R) { if(m_PrevPos.x-m_Pos.x>0) m_Core.m_Vel.x += m_Core.m_Vel.x *-0.5; - else + else if(m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2) m_Core.m_Vel.x += m_Core.m_Vel.x*0.5; } if (TileIndex1 == TILE_BOOST_D || TileIndex2 == TILE_BOOST_D) { if(m_PrevPos.y-m_Pos.y>0) m_Core.m_Vel.y += m_Core.m_Vel.y *-0.5; - else + else if(m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2) m_Core.m_Vel.y += m_Core.m_Vel.y*0.5; } if (TileIndex1 == TILE_BOOST_U || TileIndex2 == TILE_BOOST_U) { if(m_PrevPos.y-m_Pos.y<0) m_Core.m_Vel.y += m_Core.m_Vel.y *-0.5; - else + else if(m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2) m_Core.m_Vel.y += m_Core.m_Vel.y*0.5; } - if (TileIndex1 == TILE_BOOST_L2 || TileIndex2 == TILE_BOOST_L2) + if ((TileIndex1 == TILE_BOOST_L2 || TileIndex2 == TILE_BOOST_L2) && (m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2)) { if(m_PrevPos.x-m_Pos.x<0) m_Core.m_Vel.x = m_Core.m_Vel.x *-1.1; else m_Core.m_Vel.x += m_Core.m_Vel.x*1.1; } - if (TileIndex1 == TILE_BOOST_R2|| TileIndex2 == TILE_BOOST_R2) + if ((TileIndex1 == TILE_BOOST_R2|| TileIndex2 == TILE_BOOST_R2) && (m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2)) { if(m_PrevPos.x-m_Pos.x>0) m_Core.m_Vel.x = m_Core.m_Vel.x *-1.1; else m_Core.m_Vel.x += m_Core.m_Vel.x*1.1; } - if (TileIndex1 == TILE_BOOST_D2 || TileIndex2 == TILE_BOOST_D2) + if ((TileIndex1 == TILE_BOOST_D2 || TileIndex2 == TILE_BOOST_D2) && (m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2)) { if(m_PrevPos.y-m_Pos.y>0) m_Core.m_Vel.y = m_Core.m_Vel.y *-1.1; else m_Core.m_Vel.y += m_Core.m_Vel.y*1.1; } - if (TileIndex1 == TILE_BOOST_U2 || TileIndex2 == TILE_BOOST_U2) + if ((TileIndex1 == TILE_BOOST_U2 || TileIndex2 == TILE_BOOST_U2) && (m_LastBooster != TileIndex1 || m_LastFBooster != TileIndex2)) { if(m_PrevPos.y-m_Pos.y<0) m_Core.m_Vel.y = m_Core.m_Vel.y *-1.1; else m_Core.m_Vel.y += m_Core.m_Vel.y*1.1; } + m_LastBooster = TileIndex1; + m_LastFBooster = TileIndex2; + // handle speedup tiles if(GameServer()->Collision()->IsSpeedup((int)m_Core.m_Pos.x, (int)m_Core.m_Pos.y)) { vec2 Direction; diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 9561ecfb2..6918a76d8 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -161,7 +161,8 @@ public: int m_StartTime; int m_RefreshTime; - int m_LastSpeedup; + int m_LastBooster; + int m_LastFBooster; vec2 m_PrevPos; // checkpoints diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 96b456239..76276947b 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -248,7 +248,6 @@ void CPlayer::LoadCharacter() { Character->m_Armor = m_PauseInfo.m_Armor; Character->m_PlayerState = m_PauseInfo.m_PlayerState; Character->m_LastMove = m_PauseInfo.m_LastMove; - Character->m_LastSpeedup = m_PauseInfo.m_LastSpeedup; Character->m_PrevPos = m_PauseInfo.m_PrevPos; Character->m_ActiveWeapon = m_PauseInfo.m_ActiveWeapon; Character->m_LastWeapon = m_PauseInfo.m_LastWeapon; @@ -276,7 +275,6 @@ void CPlayer::SaveCharacter() m_PauseInfo.m_Armor = Character->m_Armor; m_PauseInfo.m_PlayerState = Character->m_PlayerState; m_PauseInfo.m_LastMove = Character->m_LastMove; - m_PauseInfo.m_LastSpeedup = Character->m_LastSpeedup; m_PauseInfo.m_PrevPos = Character->m_PrevPos; m_PauseInfo.m_ActiveWeapon = Character->m_ActiveWeapon; m_PauseInfo.m_LastWeapon = Character->m_LastWeapon; diff --git a/src/game/server/player.h b/src/game/server/player.h index 64ad17309..095b66d2f 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -48,7 +48,6 @@ public: int m_Armor; int m_PlayerState; int m_LastMove; - int m_LastSpeedup; vec2 m_PrevPos; int m_ActiveWeapon; int m_LastWeapon; From 572f705a12930869e0ceb9bc8b0cf869393e9a46 Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Tue, 24 Aug 2010 03:41:07 +0200 Subject: [PATCH 4/8] Added missing files Signed-off-by: GreYFoXGTi --- src/game/server/score/sql_score.cpp | 519 ++++++++++++++++++++++++++++ src/game/server/score/sql_score.h | 73 ++++ 2 files changed, 592 insertions(+) create mode 100644 src/game/server/score/sql_score.cpp create mode 100644 src/game/server/score/sql_score.h diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp new file mode 100644 index 000000000..aee288fe5 --- /dev/null +++ b/src/game/server/score/sql_score.cpp @@ -0,0 +1,519 @@ +/* CSqlScore class by Sushi */ +#include + +#include +#include "../entities/character.h" +#include "../gamemodes/race.h" +#include "sql_score.h" + +static LOCK gs_SqlLock = 0; + +CSqlScore::CSqlScore(CGameContext *pGameServer) +: m_pGameServer(pGameServer), + m_pServer(pGameServer->Server()), + m_pDatabase(g_Config.m_SvSqlDatabase), + m_pPrefix(g_Config.m_SvSqlPrefix), + m_pUser(g_Config.m_SvSqlUser), + m_pPass(g_Config.m_SvSqlPw), + m_pIp(g_Config.m_SvSqlIp), + m_Port(g_Config.m_SvSqlPort) +{ + str_copy(m_aMap, g_Config.m_SvMap, sizeof(m_aMap)); + ClearString(m_aMap); + + if(gs_SqlLock == 0) + gs_SqlLock = lock_create(); + + Init(); +} + +CSqlScore::~CSqlScore() +{ + lock_wait(gs_SqlLock); + lock_release(gs_SqlLock); +} + +bool CSqlScore::Connect() +{ + try + { + // Create connection + m_pDriver = get_driver_instance(); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "tcp://%s:%d", m_pIp, m_Port); + m_pConnection = m_pDriver->connect(aBuf, m_pUser, m_pPass); + + // Create Statement + m_pStatement = m_pConnection->createStatement(); + + // Create database if not exists + str_format(aBuf, sizeof(aBuf), "CREATE DATABASE IF NOT EXISTS %s", m_pDatabase); + m_pStatement->execute(aBuf); + + // Connect to specific database + m_pConnection->setSchema(m_pDatabase); + dbg_msg("SQL", "SQL connection established"); + return true; + } + catch (sql::SQLException &e) + { + dbg_msg("SQL", "ERROR: SQL connection failed"); + return false; + } + return false; +} + +void CSqlScore::Disconnect() +{ + try + { + delete m_pConnection; + dbg_msg("SQL", "SQL connection disconnected"); + } + catch (sql::SQLException &e) + { + dbg_msg("SQL", "ERROR: No SQL connection"); + } +} + +// create tables... should be done only once +void CSqlScore::Init() +{ + // create connection + if(Connect()) + { + try + { + // create tables + char aBuf[768]; + str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_%s_race (Name VARCHAR(31) NOT NULL, Time FLOAT DEFAULT 0, IP VARCHAR(16) DEFAULT '0.0.0.0', cp1 FLOAT DEFAULT 0, cp2 FLOAT DEFAULT 0, cp3 FLOAT DEFAULT 0, cp4 FLOAT DEFAULT 0, cp5 FLOAT DEFAULT 0, cp6 FLOAT DEFAULT 0, cp7 FLOAT DEFAULT 0, cp8 FLOAT DEFAULT 0, cp9 FLOAT DEFAULT 0, cp10 FLOAT DEFAULT 0, cp11 FLOAT DEFAULT 0, cp12 FLOAT DEFAULT 0, cp13 FLOAT DEFAULT 0, cp14 FLOAT DEFAULT 0, cp15 FLOAT DEFAULT 0, cp16 FLOAT DEFAULT 0, cp17 FLOAT DEFAULT 0, cp18 FLOAT DEFAULT 0, cp19 FLOAT DEFAULT 0, cp20 FLOAT DEFAULT 0, cp21 FLOAT DEFAULT 0, cp22 FLOAT DEFAULT 0, cp23 FLOAT DEFAULT 0, cp24 FLOAT DEFAULT 0, cp25 FLOAT DEFAULT 0);", m_pPrefix, m_aMap); + m_pStatement->execute(aBuf); + dbg_msg("SQL", "Tables were created successfully"); + + // get the best time + str_format(aBuf, sizeof(aBuf), "SELECT Time FROM %s_%s_race ORDER BY `Time` ASC LIMIT 0, 1;", m_pPrefix, m_aMap); + m_pResults = m_pStatement->executeQuery(aBuf); + + if(m_pResults->next()) + { + ((CGameControllerRACE*)GameServer()->m_pController)->m_CurrentRecord = (float)m_pResults->getDouble("Time"); + + dbg_msg("SQL", "Getting best time on server done"); + + // delete results + delete m_pResults; + } + + // delete statement + delete m_pStatement; + } + catch (sql::SQLException &e) + { + dbg_msg("SQL", "ERROR: Tables were NOT created"); + } + + // disconnect from database + Disconnect(); + } +} + +// update stuff +void CSqlScore::LoadScoreThread(void *pUser) +{ + lock_wait(gs_SqlLock); + + CSqlScoreData *pData = (CSqlScoreData *)pUser; + + // Connect to database + if(pData->m_pSqlData->Connect()) + { + try + { + // check strings + pData->m_pSqlData->ClearString(pData->m_aName); + + char aBuf[512]; + // check if there is an entry with the same ip + if(g_Config.m_SvScoreIP) + { + str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aIP); + pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); + + if(pData->m_pSqlData->m_pResults->next()) + { + // get the best time + pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_BestTime = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); + char aColumn[8]; + for(int i = 0; i < NUM_TELEPORT; i++) + { + str_format(aColumn, sizeof(aColumn), "cp%d", i+1); + pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_aBestCpTime[i] = (float)pData->m_pSqlData->m_pResults->getDouble(aColumn); + } + + dbg_msg("SQL", "Getting best time done"); + + // delete statement and results + delete pData->m_pSqlData->m_pStatement; + delete pData->m_pSqlData->m_pResults; + + // disconnect from database + pData->m_pSqlData->Disconnect(); + + delete pData; + + lock_release(gs_SqlLock); + + return; + } + + } + + str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName); + pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); + if(pData->m_pSqlData->m_pResults->next()) + { + // check if IP differs + const char* pIP = pData->m_pSqlData->m_pResults->getString("IP").c_str(); + if(str_comp(pIP, pData->m_aIP) != 0) + { + // set the new ip + str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET IP='%s' WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aIP, pData->m_aName); + pData->m_pSqlData->m_pStatement->execute(aBuf); + } + + // get the best time + pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_BestTime = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); + char aColumn[8]; + if(g_Config.m_SvCheckpointSave) + { + for(int i = 0; i < NUM_TELEPORT; i++) + { + str_format(aColumn, sizeof(aColumn), "cp%d", i+1); + pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_aBestCpTime[i] = (float)pData->m_pSqlData->m_pResults->getDouble(aColumn); + } + } + } + + dbg_msg("SQL", "Getting best time done"); + + // delete statement and results + delete pData->m_pSqlData->m_pStatement; + delete pData->m_pSqlData->m_pResults; + } + catch (sql::SQLException &e) + { + dbg_msg("SQL", "ERROR: Could not update account"); + } + + // disconnect from database + pData->m_pSqlData->Disconnect(); + } + + delete pData; + + lock_release(gs_SqlLock); +} + +void CSqlScore::LoadScore(int ClientID) +{ + CSqlScoreData *Tmp = new CSqlScoreData(); + Tmp->m_ClientID = ClientID; + str_copy(Tmp->m_aName, Server()->ClientName(ClientID), sizeof(Tmp->m_aName)); + Server()->GetClientIP(ClientID, Tmp->m_aIP, sizeof(Tmp->m_aIP)); + Tmp->m_pSqlData = this; + + void *LoadThread = thread_create(LoadScoreThread, Tmp); +#if defined(CONF_FAMILY_UNIX) + pthread_detach((pthread_t)LoadThread); +#endif +} + +void CSqlScore::SaveScoreThread(void *pUser) +{ + lock_wait(gs_SqlLock); + + CSqlScoreData *pData = (CSqlScoreData *)pUser; + + // Connect to database + if(pData->m_pSqlData->Connect()) + { + try + { + // check strings + pData->m_pSqlData->ClearString(pData->m_aName); + + char aBuf[768]; + + // fisrt check for IP + str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aIP); + pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); + + // if ip found... + if(pData->m_pSqlData->m_pResults->next()) + { + // update time + if(g_Config.m_SvCheckpointSave) + str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET Name='%s', Time='%.2f', cp1='%.2f', cp2='%.2f', cp3='%.2f', cp4='%.2f', cp5='%.2f', cp6='%.2f', cp7='%.2f', cp8='%.2f', cp9='%.2f', cp10='%.2f', cp11='%.2f', cp12='%.2f', cp13='%.2f', cp14='%.2f', cp15='%.2f', cp16='%.2f', cp17='%.2f', cp18='%.2f', cp19='%.2f', cp20='%.2f', cp21='%.2f', cp22='%.2f', cp23='%.2f', cp24='%.2f', cp25='%.2f' WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_Time, pData->m_aCpCurrent[0], pData->m_aCpCurrent[1], pData->m_aCpCurrent[2], pData->m_aCpCurrent[3], pData->m_aCpCurrent[4], pData->m_aCpCurrent[5], pData->m_aCpCurrent[6], pData->m_aCpCurrent[7], pData->m_aCpCurrent[8], pData->m_aCpCurrent[9], pData->m_aCpCurrent[10], pData->m_aCpCurrent[11], pData->m_aCpCurrent[12], pData->m_aCpCurrent[13], pData->m_aCpCurrent[14], pData->m_aCpCurrent[15], pData->m_aCpCurrent[16], pData->m_aCpCurrent[17], pData->m_aCpCurrent[18], pData->m_aCpCurrent[19], pData->m_aCpCurrent[20], pData->m_aCpCurrent[21], pData->m_aCpCurrent[22], pData->m_aCpCurrent[23], pData->m_aCpCurrent[24], pData->m_aIP); + else + str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET Name='%s', Time='%.2f' WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_Time, pData->m_aIP); + pData->m_pSqlData->m_pStatement->execute(aBuf); + + dbg_msg("SQL", "Updateing time done"); + + // delete results statement + delete pData->m_pSqlData->m_pResults; + delete pData->m_pSqlData->m_pStatement; + + // disconnect from database + pData->m_pSqlData->Disconnect(); + + delete pData; + + lock_release(gs_SqlLock); + + return; + } + + // if no entry found... create a new one + str_format(aBuf, sizeof(aBuf), "INSERT IGNORE INTO %s_%s_race(Name, IP, Time, cp1, cp2, cp3, cp4, cp5, cp6, cp7, cp8, cp9, cp10, cp11, cp12, cp13, cp14, cp15, cp16, cp17, cp18, cp19, cp20, cp21, cp22, cp23, cp24, cp25) VALUES ('%s', '%s', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f');", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_aIP, pData->m_Time, pData->m_aCpCurrent[0], pData->m_aCpCurrent[1], pData->m_aCpCurrent[2], pData->m_aCpCurrent[3], pData->m_aCpCurrent[4], pData->m_aCpCurrent[5], pData->m_aCpCurrent[6], pData->m_aCpCurrent[7], pData->m_aCpCurrent[8], pData->m_aCpCurrent[9], pData->m_aCpCurrent[10], pData->m_aCpCurrent[11], pData->m_aCpCurrent[12], pData->m_aCpCurrent[13], pData->m_aCpCurrent[14], pData->m_aCpCurrent[15], pData->m_aCpCurrent[16], pData->m_aCpCurrent[17], pData->m_aCpCurrent[18], pData->m_aCpCurrent[19], pData->m_aCpCurrent[20], pData->m_aCpCurrent[21], pData->m_aCpCurrent[22], pData->m_aCpCurrent[23], pData->m_aCpCurrent[24]); + pData->m_pSqlData->m_pStatement->execute(aBuf); + + dbg_msg("SQL", "Updateing time done"); + + // delete results statement + delete pData->m_pSqlData->m_pResults; + delete pData->m_pSqlData->m_pStatement; + } + catch (sql::SQLException &e) + { + dbg_msg("SQL", "ERROR: Could not update time"); + } + + // disconnect from database + pData->m_pSqlData->Disconnect(); + } + + delete pData; + + lock_release(gs_SqlLock); +} + +void CSqlScore::SaveScore(int ClientID, float Time, CCharacter *pChar) +{ + CSqlScoreData *Tmp = new CSqlScoreData(); + Tmp->m_ClientID = ClientID; + str_copy(Tmp->m_aName, Server()->ClientName(ClientID), sizeof(Tmp->m_aName)); + Server()->GetClientIP(ClientID, Tmp->m_aIP, sizeof(Tmp->m_aIP)); + Tmp->m_Time = Time; + for(int i = 0; i < NUM_TELEPORT; i++) + Tmp->m_aCpCurrent[i] = pChar->m_CpCurrent[i]; + Tmp->m_pSqlData = this; + + void *SaveThread = thread_create(SaveScoreThread, Tmp); +#if defined(CONF_FAMILY_UNIX) + pthread_detach((pthread_t)SaveThread); +#endif +} + +void CSqlScore::ShowRankThread(void *pUser) +{ + lock_wait(gs_SqlLock); + + CSqlScoreData *pData = (CSqlScoreData *)pUser; + + // Connect to database + if(pData->m_pSqlData->Connect()) + { + try + { + // check strings + pData->m_pSqlData->ClearString(pData->m_aName); + + // check sort methode + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "SELECT Name, IP, Time FROM %s_%s_race ORDER BY `Time` ASC;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap); + pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); + int RowCount = 0; + bool Found = false; + while(pData->m_pSqlData->m_pResults->next()) + { + RowCount++; + + if(pData->m_Search) + { + if(str_find_nocase(pData->m_pSqlData->m_pResults->getString("Name").c_str(), pData->m_aName)) + { + Found = true; + break; + } + } + else if(!str_comp(pData->m_pSqlData->m_pResults->getString("IP").c_str(), pData->m_aIP)) + { + Found = true; + break; + } + } + + if(!Found) + { + str_format(aBuf, sizeof(aBuf), "%s is not ranked", pData->m_aName); + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); + } + else + { + float Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); + if(!g_Config.m_SvShowTimes) + str_format(aBuf, sizeof(aBuf), "Your time: %d minute(s) %5.2f second(s)", (int)(Time/60), Time-((int)Time/60*60)); + else + str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %5.2f second(s)", RowCount, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60)); + + if(pData->m_Search) + strcat(aBuf, pData->m_aRequestingPlayer); + + pData->m_pSqlData->GameServer()->SendChatTarget(-1, aBuf); + } + + dbg_msg("SQL", "Showing rank done"); + + // delete results and statement + delete pData->m_pSqlData->m_pResults; + delete pData->m_pSqlData->m_pStatement; + } + catch (sql::SQLException &e) + { + dbg_msg("SQL", "ERROR: Could not show rank"); + } + + // disconnect from database + pData->m_pSqlData->Disconnect(); + } + + delete pData; + + lock_release(gs_SqlLock); +} + +void CSqlScore::ShowRank(int ClientID, const char* pName, bool Search) +{ + CSqlScoreData *Tmp = new CSqlScoreData(); + Tmp->m_ClientID = ClientID; + str_copy(Tmp->m_aName, pName, sizeof(Tmp->m_aName)); + Server()->GetClientIP(ClientID, Tmp->m_aIP, sizeof(Tmp->m_aIP)); + Tmp->m_Search = Search; + str_format(Tmp->m_aRequestingPlayer, sizeof(Tmp->m_aRequestingPlayer), " (%s)", Server()->ClientName(ClientID)); + Tmp->m_pSqlData = this; + + void *RankThread = thread_create(ShowRankThread, Tmp); +#if defined(CONF_FAMILY_UNIX) + pthread_detach((pthread_t)RankThread); +#endif +} + +void CSqlScore::ShowTop5Thread(void *pUser) +{ + lock_wait(gs_SqlLock); + + CSqlScoreData *pData = (CSqlScoreData *)pUser; + + // Connect to database + if(pData->m_pSqlData->Connect()) + { + try + { + // check sort methode + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "SELECT Name, Time FROM %s_%s_race ORDER BY `Time` ASC LIMIT %d, 5;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Num-1); + pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); + + // show top5 + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "----------- Top 5 -----------"); + + int Rank = pData->m_Num; + float Time = 0; + while(pData->m_pSqlData->m_pResults->next()) + { + Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); + str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %.2f second(s)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60)); + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); + Rank++; + } + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "------------------------------"); + + dbg_msg("SQL", "Showing top5 done"); + + // delete results and statement + delete pData->m_pSqlData->m_pResults; + delete pData->m_pSqlData->m_pStatement; + } + catch (sql::SQLException &e) + { + dbg_msg("SQL", "ERROR: Could not show top5"); + } + + // disconnect from database + pData->m_pSqlData->Disconnect(); + } + + delete pData; + + lock_release(gs_SqlLock); +} + +void CSqlScore::ShowTop5(int ClientID, int Debut) +{ + CSqlScoreData *Tmp = new CSqlScoreData(); + Tmp->m_Num = Debut; + Tmp->m_ClientID = ClientID; + Tmp->m_pSqlData = this; + + void *Top5Thread = thread_create(ShowTop5Thread, Tmp); +#if defined(CONF_FAMILY_UNIX) + pthread_detach((pthread_t)Top5Thread); +#endif +} + +// anti SQL injection +void CSqlScore::ClearString(char *pString) +{ + // replace ' ' ' with ' \' ' and remove '\' + for(int i = 0; i < str_length(pString); i++) + { + // replace '-' with '_' + if(pString[i] == '-') + pString[i] = '_'; + + if(pString[i] == '\'') + { + // count \ before the ' + int SlashCount = 0; + for(int j = i-1; j >= 0; j--) + { + if(pString[i] != '\\') + break; + + SlashCount++; + } + + if(SlashCount % 2 == 0) + { + for(int j = str_length(pString)-1; j > i; j--) + { + pString[j] = pString[j-1]; + } + pString[i] = '\\'; + i++; + } + } + } + + // aaand remove spaces and \ at the end xD + for(int i = str_length(pString)-1; i >= 0; i--) + { + if(pString[i] == ' ' || pString[i] == '\\') + pString[i] = '\0'; + else + break; + } +} + + diff --git a/src/game/server/score/sql_score.h b/src/game/server/score/sql_score.h new file mode 100644 index 000000000..1a7f0a4c2 --- /dev/null +++ b/src/game/server/score/sql_score.h @@ -0,0 +1,73 @@ +/* CSqlScore Class by Sushi */ +#ifndef GAME_SERVER_SQLSCORE_H +#define GAME_SERVER_SQLSCORE_H + +#include + +#include +#include +#include +#include + +#include "../score.h" + +class CSqlScore : public IScore +{ + CGameContext *m_pGameServer; + IServer *m_pServer; + + sql::Driver *m_pDriver; + sql::Connection *m_pConnection; + sql::Statement *m_pStatement; + sql::ResultSet *m_pResults; + + // copy of config vars + const char* m_pDatabase; + const char* m_pPrefix; + const char* m_pUser; + const char* m_pPass; + const char* m_pIp; + char m_aMap[64]; + int m_Port; + + CGameContext *GameServer() { return m_pGameServer; } + IServer *Server() { return m_pServer; } + + static void LoadScoreThread(void *pUser); + static void SaveScoreThread(void *pUser); + static void ShowRankThread(void *pUser); + static void ShowTop5Thread(void *pUser); + + void Init(); + + bool Connect(); + void Disconnect(); + + // anti SQL injection + void ClearString(char *pString); + +public: + + CSqlScore(CGameContext *pGameServer); + ~CSqlScore(); + + virtual void LoadScore(int ClientID); + virtual void SaveScore(int ClientID, float Time, CCharacter *pChar); + virtual void ShowRank(int ClientID, const char* pName, bool Search=false); + virtual void ShowTop5(int ClientID, int Debut=1); +}; + +struct CSqlScoreData +{ + CSqlScore *m_pSqlData; + int m_ClientID; + char m_aName[16]; + char m_aIP[16]; + float m_Time; + float m_aCpCurrent[NUM_TELEPORT]; + int m_Num; + bool m_Search; + char m_aRequestingPlayer[MAX_NAME_LENGTH]; +}; + +#endif From 5794680e3c7f08f277d0b690ec7d561583b9f6a0 Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Tue, 24 Aug 2010 03:45:29 +0200 Subject: [PATCH 5/8] Revert "Added missing files" This reverts commit 572f705a12930869e0ceb9bc8b0cf869393e9a46. --- src/game/server/score/sql_score.cpp | 519 ---------------------------- src/game/server/score/sql_score.h | 73 ---- 2 files changed, 592 deletions(-) delete mode 100644 src/game/server/score/sql_score.cpp delete mode 100644 src/game/server/score/sql_score.h diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp deleted file mode 100644 index aee288fe5..000000000 --- a/src/game/server/score/sql_score.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* CSqlScore class by Sushi */ -#include - -#include -#include "../entities/character.h" -#include "../gamemodes/race.h" -#include "sql_score.h" - -static LOCK gs_SqlLock = 0; - -CSqlScore::CSqlScore(CGameContext *pGameServer) -: m_pGameServer(pGameServer), - m_pServer(pGameServer->Server()), - m_pDatabase(g_Config.m_SvSqlDatabase), - m_pPrefix(g_Config.m_SvSqlPrefix), - m_pUser(g_Config.m_SvSqlUser), - m_pPass(g_Config.m_SvSqlPw), - m_pIp(g_Config.m_SvSqlIp), - m_Port(g_Config.m_SvSqlPort) -{ - str_copy(m_aMap, g_Config.m_SvMap, sizeof(m_aMap)); - ClearString(m_aMap); - - if(gs_SqlLock == 0) - gs_SqlLock = lock_create(); - - Init(); -} - -CSqlScore::~CSqlScore() -{ - lock_wait(gs_SqlLock); - lock_release(gs_SqlLock); -} - -bool CSqlScore::Connect() -{ - try - { - // Create connection - m_pDriver = get_driver_instance(); - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "tcp://%s:%d", m_pIp, m_Port); - m_pConnection = m_pDriver->connect(aBuf, m_pUser, m_pPass); - - // Create Statement - m_pStatement = m_pConnection->createStatement(); - - // Create database if not exists - str_format(aBuf, sizeof(aBuf), "CREATE DATABASE IF NOT EXISTS %s", m_pDatabase); - m_pStatement->execute(aBuf); - - // Connect to specific database - m_pConnection->setSchema(m_pDatabase); - dbg_msg("SQL", "SQL connection established"); - return true; - } - catch (sql::SQLException &e) - { - dbg_msg("SQL", "ERROR: SQL connection failed"); - return false; - } - return false; -} - -void CSqlScore::Disconnect() -{ - try - { - delete m_pConnection; - dbg_msg("SQL", "SQL connection disconnected"); - } - catch (sql::SQLException &e) - { - dbg_msg("SQL", "ERROR: No SQL connection"); - } -} - -// create tables... should be done only once -void CSqlScore::Init() -{ - // create connection - if(Connect()) - { - try - { - // create tables - char aBuf[768]; - str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_%s_race (Name VARCHAR(31) NOT NULL, Time FLOAT DEFAULT 0, IP VARCHAR(16) DEFAULT '0.0.0.0', cp1 FLOAT DEFAULT 0, cp2 FLOAT DEFAULT 0, cp3 FLOAT DEFAULT 0, cp4 FLOAT DEFAULT 0, cp5 FLOAT DEFAULT 0, cp6 FLOAT DEFAULT 0, cp7 FLOAT DEFAULT 0, cp8 FLOAT DEFAULT 0, cp9 FLOAT DEFAULT 0, cp10 FLOAT DEFAULT 0, cp11 FLOAT DEFAULT 0, cp12 FLOAT DEFAULT 0, cp13 FLOAT DEFAULT 0, cp14 FLOAT DEFAULT 0, cp15 FLOAT DEFAULT 0, cp16 FLOAT DEFAULT 0, cp17 FLOAT DEFAULT 0, cp18 FLOAT DEFAULT 0, cp19 FLOAT DEFAULT 0, cp20 FLOAT DEFAULT 0, cp21 FLOAT DEFAULT 0, cp22 FLOAT DEFAULT 0, cp23 FLOAT DEFAULT 0, cp24 FLOAT DEFAULT 0, cp25 FLOAT DEFAULT 0);", m_pPrefix, m_aMap); - m_pStatement->execute(aBuf); - dbg_msg("SQL", "Tables were created successfully"); - - // get the best time - str_format(aBuf, sizeof(aBuf), "SELECT Time FROM %s_%s_race ORDER BY `Time` ASC LIMIT 0, 1;", m_pPrefix, m_aMap); - m_pResults = m_pStatement->executeQuery(aBuf); - - if(m_pResults->next()) - { - ((CGameControllerRACE*)GameServer()->m_pController)->m_CurrentRecord = (float)m_pResults->getDouble("Time"); - - dbg_msg("SQL", "Getting best time on server done"); - - // delete results - delete m_pResults; - } - - // delete statement - delete m_pStatement; - } - catch (sql::SQLException &e) - { - dbg_msg("SQL", "ERROR: Tables were NOT created"); - } - - // disconnect from database - Disconnect(); - } -} - -// update stuff -void CSqlScore::LoadScoreThread(void *pUser) -{ - lock_wait(gs_SqlLock); - - CSqlScoreData *pData = (CSqlScoreData *)pUser; - - // Connect to database - if(pData->m_pSqlData->Connect()) - { - try - { - // check strings - pData->m_pSqlData->ClearString(pData->m_aName); - - char aBuf[512]; - // check if there is an entry with the same ip - if(g_Config.m_SvScoreIP) - { - str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aIP); - pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); - - if(pData->m_pSqlData->m_pResults->next()) - { - // get the best time - pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_BestTime = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); - char aColumn[8]; - for(int i = 0; i < NUM_TELEPORT; i++) - { - str_format(aColumn, sizeof(aColumn), "cp%d", i+1); - pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_aBestCpTime[i] = (float)pData->m_pSqlData->m_pResults->getDouble(aColumn); - } - - dbg_msg("SQL", "Getting best time done"); - - // delete statement and results - delete pData->m_pSqlData->m_pStatement; - delete pData->m_pSqlData->m_pResults; - - // disconnect from database - pData->m_pSqlData->Disconnect(); - - delete pData; - - lock_release(gs_SqlLock); - - return; - } - - } - - str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName); - pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); - if(pData->m_pSqlData->m_pResults->next()) - { - // check if IP differs - const char* pIP = pData->m_pSqlData->m_pResults->getString("IP").c_str(); - if(str_comp(pIP, pData->m_aIP) != 0) - { - // set the new ip - str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET IP='%s' WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aIP, pData->m_aName); - pData->m_pSqlData->m_pStatement->execute(aBuf); - } - - // get the best time - pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_BestTime = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); - char aColumn[8]; - if(g_Config.m_SvCheckpointSave) - { - for(int i = 0; i < NUM_TELEPORT; i++) - { - str_format(aColumn, sizeof(aColumn), "cp%d", i+1); - pData->m_pSqlData->PlayerData(pData->m_ClientID)->m_aBestCpTime[i] = (float)pData->m_pSqlData->m_pResults->getDouble(aColumn); - } - } - } - - dbg_msg("SQL", "Getting best time done"); - - // delete statement and results - delete pData->m_pSqlData->m_pStatement; - delete pData->m_pSqlData->m_pResults; - } - catch (sql::SQLException &e) - { - dbg_msg("SQL", "ERROR: Could not update account"); - } - - // disconnect from database - pData->m_pSqlData->Disconnect(); - } - - delete pData; - - lock_release(gs_SqlLock); -} - -void CSqlScore::LoadScore(int ClientID) -{ - CSqlScoreData *Tmp = new CSqlScoreData(); - Tmp->m_ClientID = ClientID; - str_copy(Tmp->m_aName, Server()->ClientName(ClientID), sizeof(Tmp->m_aName)); - Server()->GetClientIP(ClientID, Tmp->m_aIP, sizeof(Tmp->m_aIP)); - Tmp->m_pSqlData = this; - - void *LoadThread = thread_create(LoadScoreThread, Tmp); -#if defined(CONF_FAMILY_UNIX) - pthread_detach((pthread_t)LoadThread); -#endif -} - -void CSqlScore::SaveScoreThread(void *pUser) -{ - lock_wait(gs_SqlLock); - - CSqlScoreData *pData = (CSqlScoreData *)pUser; - - // Connect to database - if(pData->m_pSqlData->Connect()) - { - try - { - // check strings - pData->m_pSqlData->ClearString(pData->m_aName); - - char aBuf[768]; - - // fisrt check for IP - str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aIP); - pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); - - // if ip found... - if(pData->m_pSqlData->m_pResults->next()) - { - // update time - if(g_Config.m_SvCheckpointSave) - str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET Name='%s', Time='%.2f', cp1='%.2f', cp2='%.2f', cp3='%.2f', cp4='%.2f', cp5='%.2f', cp6='%.2f', cp7='%.2f', cp8='%.2f', cp9='%.2f', cp10='%.2f', cp11='%.2f', cp12='%.2f', cp13='%.2f', cp14='%.2f', cp15='%.2f', cp16='%.2f', cp17='%.2f', cp18='%.2f', cp19='%.2f', cp20='%.2f', cp21='%.2f', cp22='%.2f', cp23='%.2f', cp24='%.2f', cp25='%.2f' WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_Time, pData->m_aCpCurrent[0], pData->m_aCpCurrent[1], pData->m_aCpCurrent[2], pData->m_aCpCurrent[3], pData->m_aCpCurrent[4], pData->m_aCpCurrent[5], pData->m_aCpCurrent[6], pData->m_aCpCurrent[7], pData->m_aCpCurrent[8], pData->m_aCpCurrent[9], pData->m_aCpCurrent[10], pData->m_aCpCurrent[11], pData->m_aCpCurrent[12], pData->m_aCpCurrent[13], pData->m_aCpCurrent[14], pData->m_aCpCurrent[15], pData->m_aCpCurrent[16], pData->m_aCpCurrent[17], pData->m_aCpCurrent[18], pData->m_aCpCurrent[19], pData->m_aCpCurrent[20], pData->m_aCpCurrent[21], pData->m_aCpCurrent[22], pData->m_aCpCurrent[23], pData->m_aCpCurrent[24], pData->m_aIP); - else - str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET Name='%s', Time='%.2f' WHERE IP='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_Time, pData->m_aIP); - pData->m_pSqlData->m_pStatement->execute(aBuf); - - dbg_msg("SQL", "Updateing time done"); - - // delete results statement - delete pData->m_pSqlData->m_pResults; - delete pData->m_pSqlData->m_pStatement; - - // disconnect from database - pData->m_pSqlData->Disconnect(); - - delete pData; - - lock_release(gs_SqlLock); - - return; - } - - // if no entry found... create a new one - str_format(aBuf, sizeof(aBuf), "INSERT IGNORE INTO %s_%s_race(Name, IP, Time, cp1, cp2, cp3, cp4, cp5, cp6, cp7, cp8, cp9, cp10, cp11, cp12, cp13, cp14, cp15, cp16, cp17, cp18, cp19, cp20, cp21, cp22, cp23, cp24, cp25) VALUES ('%s', '%s', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f');", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_aIP, pData->m_Time, pData->m_aCpCurrent[0], pData->m_aCpCurrent[1], pData->m_aCpCurrent[2], pData->m_aCpCurrent[3], pData->m_aCpCurrent[4], pData->m_aCpCurrent[5], pData->m_aCpCurrent[6], pData->m_aCpCurrent[7], pData->m_aCpCurrent[8], pData->m_aCpCurrent[9], pData->m_aCpCurrent[10], pData->m_aCpCurrent[11], pData->m_aCpCurrent[12], pData->m_aCpCurrent[13], pData->m_aCpCurrent[14], pData->m_aCpCurrent[15], pData->m_aCpCurrent[16], pData->m_aCpCurrent[17], pData->m_aCpCurrent[18], pData->m_aCpCurrent[19], pData->m_aCpCurrent[20], pData->m_aCpCurrent[21], pData->m_aCpCurrent[22], pData->m_aCpCurrent[23], pData->m_aCpCurrent[24]); - pData->m_pSqlData->m_pStatement->execute(aBuf); - - dbg_msg("SQL", "Updateing time done"); - - // delete results statement - delete pData->m_pSqlData->m_pResults; - delete pData->m_pSqlData->m_pStatement; - } - catch (sql::SQLException &e) - { - dbg_msg("SQL", "ERROR: Could not update time"); - } - - // disconnect from database - pData->m_pSqlData->Disconnect(); - } - - delete pData; - - lock_release(gs_SqlLock); -} - -void CSqlScore::SaveScore(int ClientID, float Time, CCharacter *pChar) -{ - CSqlScoreData *Tmp = new CSqlScoreData(); - Tmp->m_ClientID = ClientID; - str_copy(Tmp->m_aName, Server()->ClientName(ClientID), sizeof(Tmp->m_aName)); - Server()->GetClientIP(ClientID, Tmp->m_aIP, sizeof(Tmp->m_aIP)); - Tmp->m_Time = Time; - for(int i = 0; i < NUM_TELEPORT; i++) - Tmp->m_aCpCurrent[i] = pChar->m_CpCurrent[i]; - Tmp->m_pSqlData = this; - - void *SaveThread = thread_create(SaveScoreThread, Tmp); -#if defined(CONF_FAMILY_UNIX) - pthread_detach((pthread_t)SaveThread); -#endif -} - -void CSqlScore::ShowRankThread(void *pUser) -{ - lock_wait(gs_SqlLock); - - CSqlScoreData *pData = (CSqlScoreData *)pUser; - - // Connect to database - if(pData->m_pSqlData->Connect()) - { - try - { - // check strings - pData->m_pSqlData->ClearString(pData->m_aName); - - // check sort methode - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "SELECT Name, IP, Time FROM %s_%s_race ORDER BY `Time` ASC;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap); - pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); - int RowCount = 0; - bool Found = false; - while(pData->m_pSqlData->m_pResults->next()) - { - RowCount++; - - if(pData->m_Search) - { - if(str_find_nocase(pData->m_pSqlData->m_pResults->getString("Name").c_str(), pData->m_aName)) - { - Found = true; - break; - } - } - else if(!str_comp(pData->m_pSqlData->m_pResults->getString("IP").c_str(), pData->m_aIP)) - { - Found = true; - break; - } - } - - if(!Found) - { - str_format(aBuf, sizeof(aBuf), "%s is not ranked", pData->m_aName); - pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); - } - else - { - float Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); - if(!g_Config.m_SvShowTimes) - str_format(aBuf, sizeof(aBuf), "Your time: %d minute(s) %5.2f second(s)", (int)(Time/60), Time-((int)Time/60*60)); - else - str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %5.2f second(s)", RowCount, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60)); - - if(pData->m_Search) - strcat(aBuf, pData->m_aRequestingPlayer); - - pData->m_pSqlData->GameServer()->SendChatTarget(-1, aBuf); - } - - dbg_msg("SQL", "Showing rank done"); - - // delete results and statement - delete pData->m_pSqlData->m_pResults; - delete pData->m_pSqlData->m_pStatement; - } - catch (sql::SQLException &e) - { - dbg_msg("SQL", "ERROR: Could not show rank"); - } - - // disconnect from database - pData->m_pSqlData->Disconnect(); - } - - delete pData; - - lock_release(gs_SqlLock); -} - -void CSqlScore::ShowRank(int ClientID, const char* pName, bool Search) -{ - CSqlScoreData *Tmp = new CSqlScoreData(); - Tmp->m_ClientID = ClientID; - str_copy(Tmp->m_aName, pName, sizeof(Tmp->m_aName)); - Server()->GetClientIP(ClientID, Tmp->m_aIP, sizeof(Tmp->m_aIP)); - Tmp->m_Search = Search; - str_format(Tmp->m_aRequestingPlayer, sizeof(Tmp->m_aRequestingPlayer), " (%s)", Server()->ClientName(ClientID)); - Tmp->m_pSqlData = this; - - void *RankThread = thread_create(ShowRankThread, Tmp); -#if defined(CONF_FAMILY_UNIX) - pthread_detach((pthread_t)RankThread); -#endif -} - -void CSqlScore::ShowTop5Thread(void *pUser) -{ - lock_wait(gs_SqlLock); - - CSqlScoreData *pData = (CSqlScoreData *)pUser; - - // Connect to database - if(pData->m_pSqlData->Connect()) - { - try - { - // check sort methode - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "SELECT Name, Time FROM %s_%s_race ORDER BY `Time` ASC LIMIT %d, 5;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Num-1); - pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); - - // show top5 - pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "----------- Top 5 -----------"); - - int Rank = pData->m_Num; - float Time = 0; - while(pData->m_pSqlData->m_pResults->next()) - { - Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); - str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %.2f second(s)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60)); - pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); - Rank++; - } - pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "------------------------------"); - - dbg_msg("SQL", "Showing top5 done"); - - // delete results and statement - delete pData->m_pSqlData->m_pResults; - delete pData->m_pSqlData->m_pStatement; - } - catch (sql::SQLException &e) - { - dbg_msg("SQL", "ERROR: Could not show top5"); - } - - // disconnect from database - pData->m_pSqlData->Disconnect(); - } - - delete pData; - - lock_release(gs_SqlLock); -} - -void CSqlScore::ShowTop5(int ClientID, int Debut) -{ - CSqlScoreData *Tmp = new CSqlScoreData(); - Tmp->m_Num = Debut; - Tmp->m_ClientID = ClientID; - Tmp->m_pSqlData = this; - - void *Top5Thread = thread_create(ShowTop5Thread, Tmp); -#if defined(CONF_FAMILY_UNIX) - pthread_detach((pthread_t)Top5Thread); -#endif -} - -// anti SQL injection -void CSqlScore::ClearString(char *pString) -{ - // replace ' ' ' with ' \' ' and remove '\' - for(int i = 0; i < str_length(pString); i++) - { - // replace '-' with '_' - if(pString[i] == '-') - pString[i] = '_'; - - if(pString[i] == '\'') - { - // count \ before the ' - int SlashCount = 0; - for(int j = i-1; j >= 0; j--) - { - if(pString[i] != '\\') - break; - - SlashCount++; - } - - if(SlashCount % 2 == 0) - { - for(int j = str_length(pString)-1; j > i; j--) - { - pString[j] = pString[j-1]; - } - pString[i] = '\\'; - i++; - } - } - } - - // aaand remove spaces and \ at the end xD - for(int i = str_length(pString)-1; i >= 0; i--) - { - if(pString[i] == ' ' || pString[i] == '\\') - pString[i] = '\0'; - else - break; - } -} - - diff --git a/src/game/server/score/sql_score.h b/src/game/server/score/sql_score.h deleted file mode 100644 index 1a7f0a4c2..000000000 --- a/src/game/server/score/sql_score.h +++ /dev/null @@ -1,73 +0,0 @@ -/* CSqlScore Class by Sushi */ -#ifndef GAME_SERVER_SQLSCORE_H -#define GAME_SERVER_SQLSCORE_H - -#include - -#include -#include -#include -#include - -#include "../score.h" - -class CSqlScore : public IScore -{ - CGameContext *m_pGameServer; - IServer *m_pServer; - - sql::Driver *m_pDriver; - sql::Connection *m_pConnection; - sql::Statement *m_pStatement; - sql::ResultSet *m_pResults; - - // copy of config vars - const char* m_pDatabase; - const char* m_pPrefix; - const char* m_pUser; - const char* m_pPass; - const char* m_pIp; - char m_aMap[64]; - int m_Port; - - CGameContext *GameServer() { return m_pGameServer; } - IServer *Server() { return m_pServer; } - - static void LoadScoreThread(void *pUser); - static void SaveScoreThread(void *pUser); - static void ShowRankThread(void *pUser); - static void ShowTop5Thread(void *pUser); - - void Init(); - - bool Connect(); - void Disconnect(); - - // anti SQL injection - void ClearString(char *pString); - -public: - - CSqlScore(CGameContext *pGameServer); - ~CSqlScore(); - - virtual void LoadScore(int ClientID); - virtual void SaveScore(int ClientID, float Time, CCharacter *pChar); - virtual void ShowRank(int ClientID, const char* pName, bool Search=false); - virtual void ShowTop5(int ClientID, int Debut=1); -}; - -struct CSqlScoreData -{ - CSqlScore *m_pSqlData; - int m_ClientID; - char m_aName[16]; - char m_aIP[16]; - float m_Time; - float m_aCpCurrent[NUM_TELEPORT]; - int m_Num; - bool m_Search; - char m_aRequestingPlayer[MAX_NAME_LENGTH]; -}; - -#endif From f6f7699ef180c416672092a223ee344ddc57c4d5 Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Tue, 24 Aug 2010 14:46:44 +0200 Subject: [PATCH 6/8] btd Fixed compiling Signed-off-by: GreYFoXGTi --- datasrc/network.py | 22 +++++- src/game/server/score.cpp | 156 -------------------------------------- 2 files changed, 21 insertions(+), 157 deletions(-) delete mode 100644 src/game/server/score.cpp diff --git a/datasrc/network.py b/datasrc/network.py index e01dba63a..d69a9879c 100644 --- a/datasrc/network.py +++ b/datasrc/network.py @@ -252,7 +252,7 @@ Messages = [ NetIntRange("m_Pass", 0, 'MAX_CLIENTS'), NetIntRange("m_Total", 0, 'MAX_CLIENTS'), ]), - + ### Client messages NetMessage("Cl_Say", [ NetBool("m_Team"), @@ -293,4 +293,24 @@ Messages = [ NetStringStrict("m_Type"), NetStringStrict("m_Value"), ]), + + NetMessage("Cl_IsRace", []), + + NetMessage("Cl_RaceShowOthers", [ + NetBool("m_Active"), + ]), + + NetMessage("Sv_RaceTime", [ + NetIntAny("m_Time"), + NetIntAny("m_Check"), + ]), + + NetMessage("Sv_Record", [ + NetIntAny("m_Time"), + ]), + + NetMessage("Sv_PlayerTime", [ + NetIntAny("m_Time"), + NetIntRange("m_Cid", 0, 'MAX_CLIENTS-1'), + ]), ] diff --git a/src/game/server/score.cpp b/src/game/server/score.cpp deleted file mode 100644 index 617c22668..000000000 --- a/src/game/server/score.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* copyright (c) 2008 rajh and gregwar. Score stuff */ - -#include "score.h" -#include "gamecontext.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -CPlayerScore::CPlayerScore(const char *name, float score) -{ - str_copy(this->name, name, sizeof(this->name)); - this->m_Score = score; -} - -std::list top; - -CScore::CScore(class CGameContext *pGameServer) -{ - m_pGameServer = pGameServer; - Load(); -} - -CScore::CScore() -{ -Load(); -} - -std::string CScore::SaveFile() -{ - std::ostringstream oss; - if(!g_Config.m_SvExternalRecords) { - oss << g_Config.m_SvMap << "_record.dtb"; - } else { - char buf[512]; - CServer* server = static_cast(m_pGameServer->Server()); - oss << server->Storage()->ApplicationSavePath() << "/records/" << g_Config.m_SvMap << "_record.dtb"; - } - return oss.str(); -} - -void CScore::Save() -{ - - std::fstream f; - f.open(SaveFile().c_str(), std::ios::out); - if(!f.fail()) { - for(std::list::iterator i=top.begin(); i!=top.end(); i++) - { - f << i->name << std::endl << i->m_Score << std::endl; - } - } - f.close(); -} - -void CScore::Load() -{ - std::fstream f; - f.open(SaveFile().c_str(), std::ios::in); - top.clear(); - while (!f.eof() && !f.fail()) - { - std::string tmpname, tmpscore; - std::getline(f, tmpname); - if(!f.eof() && tmpname != "") - { - std::getline(f, tmpscore); - top.push_back(*new CPlayerScore(tmpname.c_str(), atof(tmpscore.c_str()))); - } - } - f.close(); -} - -CPlayerScore *CScore::SearchName(const char *name, int &pos) -{ - pos=0; - for (std::list::iterator i = top.begin(); i!=top.end(); i++) - { - pos++; - if (!strcmp(i->name, name)) - { - return & (*i); - } - } - pos=-1; - return 0; -} - -CPlayerScore *CScore::SearchName(const char *name) -{ - for (std::list::iterator i = top.begin(); i!=top.end(); i++) - { - if (!strcmp(i->name, name)) - { - return & (*i); - } - } - return 0; -} - - -void CScore::ParsePlayer(const char *name, float score) -{ - Load(); - CPlayerScore *player = SearchName(name); - if (player) - { - if (player->m_Score > score) - { - player->m_Score = score; - top.sort(); - Save(); - } - } - else - { - top.push_back(*new CPlayerScore(name, score)); - top.sort(); - Save(); - } -} - -std::list CScore::Top5Draw(int id, int debut) //Thanks nevi -{ - std::list res; - int pos = 1; - //char buf[512]; - - res.push_back("----------- Top 5 -----------"); - for (std::list::iterator i = top.begin(); i != top.end() && pos <= ((debut)?4:5)+debut; i++) - { - if(i->m_Score < 0) - continue; - - if(pos >= debut) - { - std::ostringstream oss; - oss << pos << ". " << i->name << " Time: "; - - if ((int)(i->m_Score)/60 != 0) - oss << (int)(i->m_Score)/60 << ":"; - if (i->m_Score-((int)i->m_Score/60)*60 != 0) - oss << i->m_Score-((int)i->m_Score/60)*60 <<" "; - - res.push_back(oss.str()); - } - pos++; - } - res.push_back("-----------------------------"); - return res; -} From f7aa9c4c2b35c7f95a7b3341676404f3a5d53d38 Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Tue, 24 Aug 2010 16:32:46 +0200 Subject: [PATCH 7/8] ReWorked the Freeze System Signed-off-by: GreYFoXGTi --- src/game/server/entities/character.cpp | 375 ++++++++++++------------- src/game/server/entities/pickup.cpp | 8 - 2 files changed, 183 insertions(+), 200 deletions(-) diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index d9a39bb1a..17357d5fd 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -27,7 +27,7 @@ CInputCount CountInput(int Prev, int Cur) Prev &= INPUT_STATE_MASK; Cur &= INPUT_STATE_MASK; int i = Prev; - + while(i != Cur) { i = (i+1)&INPUT_STATE_MASK; @@ -80,7 +80,7 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos) m_ReckoningTick = 0; mem_zero(&m_SendCore, sizeof(m_SendCore)); mem_zero(&m_ReckoningCore, sizeof(m_ReckoningCore)); - + GameServer()->m_World.InsertEntity(this); m_Alive = true; if(m_pPlayer->m_RconFreeze) Freeze(-1); @@ -99,12 +99,12 @@ void CCharacter::SetWeapon(int W) { if(W == m_ActiveWeapon) return; - + m_LastWeapon = m_ActiveWeapon; m_QueuedWeapon = -1; m_ActiveWeapon = W; GameServer()->CreateSound(m_Pos, SOUND_WEAPON_SWITCH); - + if(m_ActiveWeapon < 0 || m_ActiveWeapon >= NUM_WEAPONS) m_ActiveWeapon = 0; } @@ -123,7 +123,7 @@ void CCharacter::HandleNinja() { if(m_ActiveWeapon != WEAPON_NINJA) return; - + vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)); if ((Server()->Tick() - m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000)) @@ -137,7 +137,7 @@ void CCharacter::HandleNinja() SetWeapon(m_ActiveWeapon); return; } - + // force ninja Weapon SetWeapon(WEAPON_NINJA); @@ -155,7 +155,7 @@ void CCharacter::HandleNinja() m_Core.m_Vel = m_Ninja.m_ActivationDir * g_pData->m_Weapons.m_Ninja.m_Velocity; vec2 OldPos = m_Pos; GameServer()->Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(m_ProximityRadius, m_ProximityRadius), 0.f); - + // reset velocity so the client doesn't predict stuff m_Core.m_Vel = vec2(0.f, 0.f); @@ -171,7 +171,7 @@ void CCharacter::HandleNinja() { if (aEnts[i] == this) continue; - + // make sure we haven't Hit this object before bool bAlreadyHit = false; for (int j = 0; j < m_NumObjectsHit; j++) @@ -191,11 +191,11 @@ void CCharacter::HandleNinja() // set his velocity to fast upward (for now) if(m_NumObjectsHit < 10) m_apHitObjects[m_NumObjectsHit++] = aEnts[i]; - + aEnts[i]->TakeDamage(vec2(0, 10.0f), g_pData->m_Weapons.m_Ninja.m_pBase->m_Damage, m_pPlayer->GetCID(), WEAPON_NINJA); } } - + return; } @@ -218,7 +218,7 @@ void CCharacter::HandleWeaponSwitch() int WantedWeapon = m_ActiveWeapon; if(m_QueuedWeapon != -1) WantedWeapon = m_QueuedWeapon; - + // select Weapon int Next = CountInput(m_LatestPrevInput.m_NextWeapon, m_LatestInput.m_NextWeapon).m_Presses; int Prev = CountInput(m_LatestPrevInput.m_PrevWeapon, m_LatestInput.m_PrevWeapon).m_Presses; @@ -250,7 +250,7 @@ void CCharacter::HandleWeaponSwitch() // check for insane values if(WantedWeapon >= 0 && WantedWeapon < NUM_WEAPONS && WantedWeapon != m_ActiveWeapon && m_aWeapons[WantedWeapon].m_Got) m_QueuedWeapon = WantedWeapon; - + DoWeaponSwitch(); } @@ -258,10 +258,10 @@ void CCharacter::FireWeapon() { if(m_ReloadTimer != 0 /*|| m_FreezeTime > 0*/) return; - + DoWeaponSwitch(); vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)); - + bool FullAuto = false; if(m_ActiveWeapon == WEAPON_GRENADE || m_ActiveWeapon == WEAPON_SHOTGUN || m_ActiveWeapon == WEAPON_RIFLE) FullAuto = true; @@ -271,13 +271,13 @@ void CCharacter::FireWeapon() bool WillFire = false; if(CountInput(m_LatestPrevInput.m_Fire, m_LatestInput.m_Fire).m_Presses) WillFire = true; - + if(FullAuto && (m_LatestInput.m_Fire&1) && m_aWeapons[m_ActiveWeapon].m_Ammo) WillFire = true; - + if(!WillFire) return; - + // check for ammo if(!m_aWeapons[m_ActiveWeapon].m_Ammo) { @@ -286,7 +286,7 @@ void CCharacter::FireWeapon() GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG); return; } - + vec2 ProjStartPos = m_Pos+Direction*m_ProximityRadius*0.75f; switch(m_ActiveWeapon) { @@ -295,18 +295,18 @@ void CCharacter::FireWeapon() // reset objects Hit m_NumObjectsHit = 0; GameServer()->CreateSound(m_Pos, SOUND_HAMMER_FIRE); - + if (!g_Config.m_SvHit) break; - + CCharacter *aEnts[64]; int Hits = 0; - int Num = GameServer()->m_World.FindEntities(ProjStartPos, m_ProximityRadius*0.5f, (CEntity**)aEnts, + int Num = GameServer()->m_World.FindEntities(ProjStartPos, m_ProximityRadius*0.5f, (CEntity**)aEnts, 64, NETOBJTYPE_CHARACTER); for (int i = 0; i < Num; ++i) { CCharacter *Target = aEnts[i]; - + //for DDRace mod or any other mod, which needs hammer hits through the wall remove second condition if ((Target == this) /*|| GameServer()->Collision()->IntersectLine(ProjStartPos, Target->m_Pos, NULL, NULL)*/) continue; @@ -314,22 +314,22 @@ void CCharacter::FireWeapon() // set his velocity to fast upward (for now) GameServer()->CreateHammerHit(m_Pos); aEnts[i]->TakeDamage(vec2(0.f, -1.f), g_pData->m_Weapons.m_Hammer.m_pBase->m_Damage, m_pPlayer->GetCID(), m_ActiveWeapon); - + vec2 Dir; if (length(Target->m_Pos - m_Pos) > 0.0f) Dir = normalize(Target->m_Pos - m_Pos); else Dir = vec2(0.f, -1.f); - + Target->m_Core.m_Vel += normalize(Dir + vec2(0.f, -1.1f)) * 10.0f * (m_HammerType + 1); Target->UnFreeze(); Hits++; } - + // if we Hit anything, we have to wait for the reload if(Hits) m_ReloadTimer = Server()->TickSpeed()/3; - + } break; case WEAPON_GUN: @@ -339,26 +339,26 @@ void CCharacter::FireWeapon() ProjStartPos, Direction, (int)(Server()->TickSpeed()*GameServer()->Tuning()->m_GunLifetime), - 0, - 0, - 0, - -1, + 0, + 0, + 0, + -1, WEAPON_GUN); - + // pack the Projectile and send it to the client Directly CNetObj_Projectile p; Proj->FillInfo(&p); - + CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE); Msg.AddInt(1); for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++) Msg.AddInt(((int *)&p)[i]); - + Server()->SendMsg(&Msg, 0, m_pPlayer->GetCID()); - + GameServer()->CreateSound(m_Pos, SOUND_GUN_FIRE); } break; - + case WEAPON_SHOTGUN: { new CLaser(&GameServer()->m_World, m_Pos, Direction, GameServer()->Tuning()->m_LaserReach, m_pPlayer->GetCID(), 1); @@ -367,7 +367,7 @@ void CCharacter::FireWeapon() CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE); Msg.AddInt(ShotSpread*2+1); - + for(int i = -ShotSpread; i <= ShotSpread; ++i) { float Spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; @@ -381,17 +381,17 @@ void CCharacter::FireWeapon() vec2(cosf(a), sinf(a))*Speed, (int)(Server()->TickSpeed()*GameServer()->Tuning()->m_Shotm_GunLifetime), 1, 0, 0, -1, WEAPON_SHOTGUN); - + // pack the Projectile and send it to the client Directly CNetObj_Projectile p; Proj->FillInfo(&p); - + for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++) Msg.AddInt(((int *)&p)[i]); } - Server()->SendMsg(&Msg, 0,m_pPlayer->GetCID()); - + Server()->SendMsg(&Msg, 0,m_pPlayer->GetCID()); + GameServer()->CreateSound(m_Pos, SOUND_SHOTGUN_FIRE);*/ } break; @@ -402,44 +402,44 @@ void CCharacter::FireWeapon() ProjStartPos, Direction, (int)(Server()->TickSpeed()*GameServer()->Tuning()->m_GrenadeLifetime), - 0, - true, - 0, + 0, + true, + 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); // pack the Projectile and send it to the client Directly CNetObj_Projectile p; Proj->FillInfo(&p); - + CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE); Msg.AddInt(1); for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++) Msg.AddInt(((int *)&p)[i]); Server()->SendMsg(&Msg, 0, m_pPlayer->GetCID()); - + GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE); } break; - + case WEAPON_RIFLE: { new CLaser(GameWorld(), m_Pos, Direction, GameServer()->Tuning()->m_LaserReach, m_pPlayer->GetCID(), 0); //GameServer()->CreateSound(m_Pos, SOUND_RIFLE_FIRE); } break; - + case WEAPON_NINJA: { // reset Hit objects m_NumObjectsHit = 0; - + m_AttackTick = Server()->Tick(); m_Ninja.m_ActivationDir = Direction; //m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000; m_Ninja.m_CurrentMoveTime = 10; //GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE); } break; - + } - + m_AttackTick = Server()->Tick(); /* if(m_aWeapons[m_ActiveWeapon].m_Ammo > 0) // -1 == unlimited @@ -453,7 +453,7 @@ void CCharacter::HandleWeapons() { //ninja HandleNinja(); - + vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)); // check reload timer @@ -495,9 +495,9 @@ void CCharacter::HandleWeapons() bool CCharacter::GiveWeapon(int Weapon, int Ammo) { if(m_aWeapons[Weapon].m_Ammo < g_pData->m_Weapons.m_aId[Weapon].m_Maxammo || !m_aWeapons[Weapon].m_Got) - { + { m_aWeapons[Weapon].m_Got = true; - m_aWeapons[Weapon].m_Ammo = min(g_pData->m_Weapons.m_aId[Weapon].m_Maxammo, Ammo); + if(!m_FreezeTime) m_aWeapons[Weapon].m_Ammo = min(g_pData->m_Weapons.m_aId[Weapon].m_Maxammo, Ammo); return true; } return false; @@ -509,7 +509,7 @@ void CCharacter::GiveNinja() GameServer()->CreateSound(m_Pos, SOUND_PICKUP_NINJA); m_Ninja.m_ActivationTick = Server()->Tick(); m_aWeapons[WEAPON_NINJA].m_Got = true; - m_aWeapons[WEAPON_NINJA].m_Ammo = -1; + if (!m_FreezeTime) m_aWeapons[WEAPON_NINJA].m_Ammo = -1; m_LastWeapon = m_ActiveWeapon; m_ActiveWeapon = WEAPON_NINJA; } @@ -525,27 +525,27 @@ void CCharacter::OnPredictedInput(CNetObj_PlayerInput *pNewInput) // check for changes if(mem_comp(&m_Input, pNewInput, sizeof(CNetObj_PlayerInput)) != 0) m_LastAction = Server()->Tick(); - + // copy new input mem_copy(&m_Input, pNewInput, sizeof(m_Input)); m_NumInputs++; - + // or are not allowed to aim in the center if(m_Input.m_TargetX == 0 && m_Input.m_TargetY == 0) - m_Input.m_TargetY = -1; + m_Input.m_TargetY = -1; } void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput) { mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput)); mem_copy(&m_LatestInput, pNewInput, sizeof(m_LatestInput)); - + if(m_NumInputs > 2 && m_pPlayer->GetTeam() != -1) { HandleWeaponSwitch(); FireWeapon(); } - + mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput)); } @@ -560,7 +560,7 @@ void CCharacter::Tick() char Buf[128]; str_format(Buf, sizeof(Buf), "You were moved to %s due to team balancing", GameServer()->m_pController->GetTeamName(m_pPlayer->GetTeam())); GameServer()->SendBroadcast(Buf, m_pPlayer->GetCID()); - + m_pPlayer->m_ForceBalanced = false; } m_Armor=(m_FreezeTime != -1)?10-(m_FreezeTime/15):0; @@ -573,14 +573,14 @@ void CCharacter::Tick() { GameServer()->CreateDamageInd(m_Pos, 0, m_FreezeTime / Server()->TickSpeed()); } - (m_FreezeTime != -1)?m_FreezeTime--:0; + if(m_FreezeTime != -1) + m_FreezeTime--; + else + m_Ninja.m_ActivationTick = Server()->Tick(); m_Input.m_Direction = 0; m_Input.m_Jump = 0; m_Input.m_Hook = 0; - m_Ninja.m_ActivationTick = Server()->Tick(); - m_aWeapons[WEAPON_NINJA].m_Got=true; - m_aWeapons[WEAPON_NINJA].m_Ammo =0; - m_ActiveWeapon=WEAPON_NINJA; + //m_Input.m_Fire = 0; if (m_FreezeTime == 1) { UnFreeze(); @@ -588,21 +588,21 @@ void CCharacter::Tick() } m_Core.m_Input = m_Input; m_Core.Tick(true); - + m_DoSplash = false; if (g_Config.m_SvEndlessDrag) m_Core.m_HookTick = 0; if (m_Super && m_Core.m_Jumped > 1) - m_Core.m_Jumped = 1; + m_Core.m_Jumped = 1; if (m_Super && g_Config.m_SvEndlessSuperHook) m_Core.m_HookTick = 0; /*dbg_msg("character","TileIndex1=%d , TileIndex2=%d",TileIndex1,TileIndex2); //REMOVE*/ - //DDRace + //DDRace char aBuftime[128]; float time = (float)(Server()->Tick() - m_StartTime) / ((float)Server()->TickSpeed()); CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID()); - if(Server()->Tick() - m_RefreshTime >= Server()->TickSpeed()) + if(Server()->Tick() - m_RefreshTime >= Server()->TickSpeed()) { if (m_RaceState == RACE_STARTED) { int IntTime = (int)time; @@ -611,7 +611,7 @@ void CCharacter::Tick() CNetMsg_Sv_RaceTime Msg; Msg.m_Time = IntTime; Msg.m_Check = 0; - + if(m_CpActive != -1 && m_CpTick > Server()->Tick()) { if(pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0) @@ -620,11 +620,11 @@ void CCharacter::Tick() Msg.m_Check = (int)Diff; } } - + Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID()); } else { str_format(aBuftime, sizeof(aBuftime), "Current Time: %d min %d sec", IntTime/60, IntTime%60); - + if(m_CpActive != -1 && m_CpTick > Server()->Tick()) { if(pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0) @@ -635,7 +635,7 @@ void CCharacter::Tick() strcat(aBuftime, aTmp); } } - + if( g_Config.m_SvBroadcast[0] != 0) { char aTmp[128]; str_format(aTmp, sizeof(aTmp), "\n%s\n", g_Config.m_SvBroadcast); @@ -650,12 +650,12 @@ void CCharacter::Tick() strcat(aBuftime, aTmp); GameServer()->SendBroadcast(g_Config.m_SvBroadcast, m_pPlayer->GetCID()); } - + } m_RefreshTime = Server()->Tick(); } - - + + int cp = GameServer()->Collision()->IsCheckpoint(MapIndex); if(cp != -1 && m_RaceState == RACE_STARTED) { @@ -678,7 +678,7 @@ void CCharacter::Tick() GameServer()->SendChatTarget(m_pPlayer->GetCID(), aBuf); else GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); - + if(time - pData->m_BestTime < 0) { // new record \o/ @@ -688,16 +688,16 @@ void CCharacter::Tick() else GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf); } - + if(!pData->m_BestTime || time < pData->m_BestTime) { // update the score pData->Set(time, m_CpCurrent); - + if(str_comp_num(Server()->ClientName(m_pPlayer->GetCID()), "nameless tee", 12) != 0) GameServer()->Score()->SaveScore(m_pPlayer->GetCID(), time, this); } - + // update server best time if(!GameServer()->m_pController->m_CurrentRecord || time < GameServer()->m_pController->m_CurrentRecord) { @@ -705,13 +705,13 @@ void CCharacter::Tick() if(str_comp_num(Server()->ClientName(m_pPlayer->GetCID()), "nameless tee", 12) != 0) GameServer()->m_pController->m_CurrentRecord = time; } - + m_RaceState = RACE_NONE; // set player score if(!GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime || GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime > time) { GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime = time; - + // send it to all players for(int i = 0; i < MAX_CLIENTS; i++) { @@ -731,11 +731,11 @@ void CCharacter::Tick() } } } - + int TTime = 0-(int)time; if(m_pPlayer->m_Score < TTime) m_pPlayer->m_Score = TTime; - + } if(((TileIndex1 == TILE_FREEZE) || (TileIndex2 == TILE_FREEZE)) && !m_Super) { @@ -884,7 +884,7 @@ void CCharacter::Tick() vec2 Direction; int Force; GameServer()->Collision()->GetSpeedup((int)m_Core.m_Pos.x, (int)m_Core.m_Pos.y, &Direction, &Force); - + m_Core.m_Vel += Direction*Force; } if(z) @@ -896,7 +896,7 @@ void CCharacter::Tick() m_Core.m_Pos = ((CGameControllerDDRace*)GameServer()->m_pController)->m_pTeleporter[z-1]; m_Core.m_HookPos = m_Core.m_Pos; } - + // handle death-tiles if((GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH || @@ -917,7 +917,7 @@ void CCharacter::Tick() { Die(m_pPlayer->GetCID(), WEAPON_WORLD); } - + // handle Weapons HandleWeapons(); @@ -928,36 +928,36 @@ void CCharacter::Tick() if (!m_Doored) { m_OlderPos = m_OldPos; - m_OldPos = m_Core.m_Pos; - } + m_OldPos = m_Core.m_Pos; + } m_PrevPos = m_Core.m_Pos; return; } -float point_distance(vec2 point, vec2 line_start, vec2 line_end) +float point_distance(vec2 point, vec2 line_start, vec2 line_end) { - float res = -1.0f; - vec2 dir = normalize(line_end-line_start); - for(int i = 0; i < length(line_end-line_start); i++) - { - vec2 step = dir; - step.x *= i; - step.y *= i; - float dist = distance(step+line_start, point); - if(res < 0 || dist < res) - res = dist; - } - return res; -} - -void CCharacter::ResetPos() -{ - m_Core.m_Pos = m_OlderPos; - //core.pos-=core.vel; - m_Core.m_Vel = vec2(0,0); - if(m_Core.m_Jumped >= 2) - m_Core.m_Jumped = 1; -} + float res = -1.0f; + vec2 dir = normalize(line_end-line_start); + for(int i = 0; i < length(line_end-line_start); i++) + { + vec2 step = dir; + step.x *= i; + step.y *= i; + float dist = distance(step+line_start, point); + if(res < 0 || dist < res) + res = dist; + } + return res; +} + +void CCharacter::ResetPos() +{ + m_Core.m_Pos = m_OlderPos; + //core.pos-=core.vel; + m_Core.m_Vel = vec2(0,0); + if(m_Core.m_Jumped >= 2) + m_Core.m_Jumped = 1; +} void CCharacter::TickDefered() { @@ -969,12 +969,12 @@ void CCharacter::TickDefered() m_ReckoningCore.Move(); m_ReckoningCore.Quantize(); } - + //lastsentcore vec2 StartPos = m_Core.m_Pos; vec2 StartVel = m_Core.m_Vel; bool StuckBefore = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f)); - + m_Core.Move(); if(m_Doored) { @@ -985,7 +985,7 @@ void CCharacter::TickDefered() m_Core.Quantize(); bool StuckAfterQuant = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f)); m_Pos = m_Core.m_Pos; - + if(!StuckBefore && (StuckAfterMove || StuckAfterQuant)) { // Hackish solution to get rid of strict-aliasing warning @@ -1000,7 +1000,7 @@ void CCharacter::TickDefered() StartVelX.f = StartVel.x; StartVelY.f = StartVel.y; - dbg_msg("char_core", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", + dbg_msg("char_core", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", StuckBefore, StuckAfterMove, StuckAfterQuant, @@ -1012,20 +1012,20 @@ void CCharacter::TickDefered() int Events = m_Core.m_TriggeredEvents; int Mask = CmaskAllExceptOne(m_pPlayer->GetCID()); - + if(Events&COREEVENT_GROUND_JUMP) GameServer()->CreateSound(m_Pos, SOUND_PLAYER_JUMP, Mask); - + if(Events&COREEVENT_HOOK_ATTACH_PLAYER) GameServer()->CreateSound(m_Pos, SOUND_HOOK_ATTACH_PLAYER, CmaskAll()); if(Events&COREEVENT_HOOK_ATTACH_GROUND) GameServer()->CreateSound(m_Pos, SOUND_HOOK_ATTACH_GROUND, Mask); if(Events&COREEVENT_HOOK_HIT_NOHOOK) GameServer()->CreateSound(m_Pos, SOUND_HOOK_NOATTACH, Mask); - + if(m_pPlayer->GetTeam() == -1) { m_Pos.x = m_Input.m_TargetX; m_Pos.y = m_Input.m_TargetY; } - + // update the m_SendCore if needed { CNetObj_Character Predicted; @@ -1047,80 +1047,70 @@ void CCharacter::TickDefered() } bool CCharacter::Freeze(int Time) -{ +{ if ((Time <= 1 || m_Super || m_FreezeTime == -1) && Time != -1) - return false; + return false; if (m_FreezeTick < Server()->Tick() - Server()->TickSpeed()) { + for(int i=0;iTick(); - m_aWeapons[WEAPON_NINJA].m_Got = true; - m_aWeapons[WEAPON_NINJA].m_Ammo = 0; - m_LastWeapon = m_ActiveWeapon; - m_ActiveWeapon = WEAPON_NINJA; - m_FreezeTick=Server()->Tick(); m_FreezeTime=Time; + m_FreezeTick=Server()->Tick(); return true; - } - return false; -} - -bool CCharacter::Freeze() -{ + } + return false; +} + +bool CCharacter::Freeze() +{ int Time = Server()->TickSpeed()*3; if (Time <= 1 || m_Super || m_FreezeTime == -1) - return false; + return false; if (m_FreezeTick < Server()->Tick() - Server()->TickSpeed()) { + for(int i=0;iTick(); - m_aWeapons[WEAPON_NINJA].m_Got = true; - m_aWeapons[WEAPON_NINJA].m_Ammo = 0; - m_LastWeapon = m_ActiveWeapon; - m_ActiveWeapon = WEAPON_NINJA; - m_FreezeTick=Server()->Tick(); m_FreezeTime=Time; + m_FreezeTick=Server()->Tick(); return true; - } - return false; -} - -bool CCharacter::UnFreeze() -{ + } + return false; +} + +bool CCharacter::UnFreeze() +{ if (m_FreezeTime>0) { m_Armor=10; - m_FreezeTick=0; + for(int i=0;iCreateSound(m_Pos, SOUND_PLAYER_DIE); - + // this is for auto respawn after 3 secs m_pPlayer->m_DieTick = Server()->Tick(); - + m_Alive = false; GameServer()->m_World.RemoveEntity(this); GameServer()->m_World.m_Core.m_apCharacters[m_pPlayer->GetCID()] = 0; GameServer()->CreateDeath(m_Pos, m_pPlayer->GetCID()); - + // we got to wait 0.5 secs before respawning m_pPlayer->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2; } @@ -1203,7 +1193,7 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon) m_Health--; Dmg--; } - + if(Dmg > m_Armor) { Dmg -= m_Armor; @@ -1215,7 +1205,7 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon) Dmg = 0; } } - + m_Health -= Dmg; } @@ -1229,9 +1219,9 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon) if(m_Health <= 0) { Die(From, Weapon); - - + + return false; } @@ -1263,9 +1253,9 @@ void CCharacter::Snap(int SnappingClient) { if(NetworkClipped(SnappingClient)) return; - + CNetObj_Character *Character = static_cast(Server()->SnapNewItem(NETOBJTYPE_CHARACTER, m_pPlayer->GetCID(), sizeof(CNetObj_Character))); - + // write down the m_Core if(!m_ReckoningTick || GameServer()->m_World.m_Paused) { @@ -1279,7 +1269,7 @@ void CCharacter::Snap(int SnappingClient) Character->m_Tick = m_ReckoningTick; m_SendCore.Write(Character); } - + if(m_DoSplash) { Character->m_Jumped = 3; } @@ -1295,13 +1285,14 @@ void CCharacter::Snap(int SnappingClient) Character->m_AmmoCount = 0; Character->m_Health = 0; Character->m_Armor = 0; - - if (m_FreezeTime > 0) - { - Character->m_Emote = EMOTE_PAIN; - Character->m_Weapon = WEAPON_NINJA; + + if (m_FreezeTime > 0 || m_FreezeTime == -1) + { + Character->m_Emote = EMOTE_PAIN; + Character->m_Weapon = WEAPON_NINJA; + Character->m_AmmoCount = 0; } - else + else Character->m_Weapon = m_ActiveWeapon; Character->m_AttackTick = m_AttackTick; @@ -1312,7 +1303,7 @@ void CCharacter::Snap(int SnappingClient) Character->m_Health = m_Health; Character->m_Armor = m_Armor; if(m_aWeapons[m_ActiveWeapon].m_Ammo > 0) - Character->m_AmmoCount = m_aWeapons[m_ActiveWeapon].m_Ammo; + Character->m_AmmoCount = (!m_FreezeTime)?m_aWeapons[m_ActiveWeapon].m_Ammo:0; } if (Character->m_Emote == EMOTE_NORMAL) diff --git a/src/game/server/entities/pickup.cpp b/src/game/server/entities/pickup.cpp index 9d34ac131..1cd4de871 100644 --- a/src/game/server/entities/pickup.cpp +++ b/src/game/server/entities/pickup.cpp @@ -79,14 +79,6 @@ void CPickup::Tick() sound = true; } } - if(pChr->m_FreezeTime) - { - pChr->m_aWeapons[WEAPON_GUN].m_Ammo = 0; - pChr->m_aWeapons[WEAPON_HAMMER].m_Ammo =0; - } - pChr->m_Ninja.m_ActivationDir=vec2(0,0); - pChr->m_Ninja.m_ActivationTick=0; - pChr->m_Ninja.m_CurrentMoveTime=0; } if (sound) { From 03bb17e580e1fd4a17216ebb34584396230c629e Mon Sep 17 00:00:00 2001 From: GreYFoXGTi Date: Tue, 24 Aug 2010 17:13:26 +0200 Subject: [PATCH 8/8] fixed ninja not being remembered after freeze Signed-off-by: GreYFoXGTi --- src/game/server/entities/character.cpp | 1 + src/game/server/entities/pickup.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 17357d5fd..02c39a982 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -1096,6 +1096,7 @@ bool CCharacter::UnFreeze() { m_aWeapons[i].m_Ammo = -1; } + if(!m_aWeapons[m_ActiveWeapon].m_Got) m_ActiveWeapon=WEAPON_GUN; m_FreezeTime=0; return true; } diff --git a/src/game/server/entities/pickup.cpp b/src/game/server/entities/pickup.cpp index 1cd4de871..c748cb50c 100644 --- a/src/game/server/entities/pickup.cpp +++ b/src/game/server/entities/pickup.cpp @@ -80,6 +80,9 @@ void CPickup::Tick() } } } + pChr->m_Ninja.m_ActivationDir=vec2(0,0); + pChr->m_Ninja.m_ActivationTick=-500; + pChr->m_Ninja.m_CurrentMoveTime=0; if (sound) { pChr->m_LastWeapon = WEAPON_GUN; @@ -90,7 +93,7 @@ void CPickup::Tick() case POWERUP_WEAPON: - if(m_Subtype >= 0 && m_Subtype < NUM_WEAPONS && (!pChr->m_aWeapons[m_Subtype].m_Got || pChr->m_aWeapons[m_Subtype].m_Ammo != -1)) + if(m_Subtype >= 0 && m_Subtype < NUM_WEAPONS && (!pChr->m_aWeapons[m_Subtype].m_Got || (pChr->m_aWeapons[m_Subtype].m_Ammo != -1 && !pChr->m_FreezeTime))) { if(pChr->GiveWeapon(m_Subtype, -1)) {