ddnet/src/game/server/ddracecommands.cpp
bors[bot] be7242e010
Merge #6071 #6077 #6085 #6088 #6090
6071: Add logs for moderators (fixes #5433) r=def- a=Vy0x2

<!-- What is the motivation for the changes of this pull request? -->
issue #5433 
Moderators can access the last x minutes of the chat activity.
Every entry beside server messages will show the player name, player ip and client who wrote the message / who disconnected so moderators can get the players ip after something happened in case he left already.

The current implementation has a 4 minute time slot, messages older than 4 minutes are not shown.
To limit the memory usage its limited atm to 256 log-entries. In case of more messages than 256 in 4 minutes (unlikely), the oldest messages are overwritten.

I keep this as a draft for a while, because its my first pr and I am sure there is some improvement i did not see (or to improve the wording)
<!-- Note that builds and other checks will be run for your change. Don't feel intimidated by failures in some of the checks. If you can't resolve them yourself, experienced devs can also resolve them before merging your pull request. -->

## Checklist

- [x] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [x] Considered possible null pointers and out of bounds array indexing
- [x] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


6077: Add "Tools > Remove unused envelopes" to editor r=def- a=Robyt3

Add a new menu "Tools" next to the "File" menu, with a button to "Remove unused envelopes".

Clicking the button opens a confirmation popup to confirm the operation.

![editor-tools-menu](https://user-images.githubusercontent.com/23437060/205157109-62d53601-502a-4401-8c6f-f06c7e57e174.png)

Closes #2576.

## Checklist

- [X] Tested the change ingame
- [X] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


6085: Fix cmake args in workspace r=def- a=Jupeyy

current is completely wrong, since it overwrites the cmake internal settings. and e.g. prevent `-g`
Now it should in worst case only overwrite custom settings by the user. but dunno how often u actually do that anyway inside a IDE

but if someone knows better I'm glad to hear it

## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


6088: Pr fix uninit r=def- a=Jupeyy

<!-- What is the motivation for the changes of this pull request? -->

<!-- Note that builds and other checks will be run for your change. Don't feel intimidated by failures in some of the checks. If you can't resolve them yourself, experienced devs can also resolve them before merging your pull request. -->

## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


6090: FIX: parse & colorify gametype Gores correctly r=heinrich5991 a=Avolicious

`@def-` The correct PR now :) Correct coloring the gamemode "Gores"
![193410660-5e757fd4-449f-4d0a-a719-4a0cc1e5a01e](https://user-images.githubusercontent.com/105295486/205684472-36cc6daa-bda4-4af1-a838-b7fe25a55dec.png)

## Checklist

- [x] Tested the change ingame
- [x] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [x] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Vy0x2 <denispaul43@gmail.com>
Co-authored-by: Robert Müller <robytemueller@gmail.com>
Co-authored-by: Jupeyy <jupjopjap@gmail.com>
Co-authored-by: Avolicious <avolicious@kog.tw>
2022-12-05 16:12:05 +00:00

876 lines
26 KiB
C++

/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
#include "gamecontext.h"
#include <engine/antibot.h>
#include <engine/shared/config.h>
#include <game/server/entities/character.h>
#include <game/server/gamemodes/DDRace.h>
#include <game/server/player.h>
#include <game/server/save.h>
#include <game/server/teams.h>
bool CheckClientID(int ClientID);
void CGameContext::ConGoLeft(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, -1, 0);
}
void CGameContext::ConGoRight(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, 1, 0);
}
void CGameContext::ConGoDown(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, 0, 1);
}
void CGameContext::ConGoUp(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, 0, -1);
}
void CGameContext::ConMove(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, pResult->GetInteger(0),
pResult->GetInteger(1));
}
void CGameContext::ConMoveRaw(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
pSelf->MoveCharacter(pResult->m_ClientID, pResult->GetInteger(0),
pResult->GetInteger(1), true);
}
void CGameContext::MoveCharacter(int ClientID, int X, int Y, bool Raw)
{
CCharacter *pChr = GetPlayerChar(ClientID);
if(!pChr)
return;
pChr->Core()->m_Pos.x += ((Raw) ? 1 : 32) * X;
pChr->Core()->m_Pos.y += ((Raw) ? 1 : 32) * Y;
pChr->m_DDRaceState = DDRACE_CHEAT;
}
void CGameContext::ConKillPlayer(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
int Victim = pResult->GetVictim();
if(pSelf->m_apPlayers[Victim])
{
pSelf->m_apPlayers[Victim]->KillCharacter(WEAPON_GAME);
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "%s was killed by %s",
pSelf->Server()->ClientName(Victim),
pSelf->Server()->ClientName(pResult->m_ClientID));
pSelf->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
}
}
void CGameContext::ConNinja(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_NINJA, false);
}
void CGameContext::ConEndlessHook(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
pChr->SetEndlessHook(true);
}
}
void CGameContext::ConUnEndlessHook(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
pChr->SetEndlessHook(false);
}
}
void CGameContext::ConSuper(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr && !pChr->IsSuper())
{
pChr->SetSuper(true);
pChr->UnFreeze();
}
}
void CGameContext::ConUnSuper(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr && pChr->IsSuper())
{
pChr->SetSuper(false);
}
}
void CGameContext::ConUnSolo(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetSolo(false);
}
void CGameContext::ConUnDeep(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetDeepFrozen(false);
}
void CGameContext::ConLiveFreeze(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetLiveFrozen(true);
}
void CGameContext::ConUnLiveFreeze(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetLiveFrozen(false);
}
void CGameContext::ConShotgun(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_SHOTGUN, false);
}
void CGameContext::ConGrenade(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_GRENADE, false);
}
void CGameContext::ConLaser(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_LASER, false);
}
void CGameContext::ConJetpack(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetJetpack(true);
}
void CGameContext::ConWeapons(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, -1, false);
}
void CGameContext::ConUnShotgun(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_SHOTGUN, true);
}
void CGameContext::ConUnGrenade(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_GRENADE, true);
}
void CGameContext::ConUnLaser(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, WEAPON_LASER, true);
}
void CGameContext::ConUnJetpack(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
pChr->SetJetpack(false);
}
void CGameContext::ConUnWeapons(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, -1, true);
}
void CGameContext::ConAddWeapon(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, pResult->GetInteger(0), false);
}
void CGameContext::ConRemoveWeapon(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ModifyWeapons(pResult, pUserData, pResult->GetInteger(0), true);
}
void CGameContext::ModifyWeapons(IConsole::IResult *pResult, void *pUserData,
int Weapon, bool Remove)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = GetPlayerChar(pResult->m_ClientID);
if(!pChr)
return;
if(clamp(Weapon, -1, NUM_WEAPONS - 1) != Weapon)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "info",
"invalid weapon id");
return;
}
if(Weapon == -1)
{
pChr->GiveWeapon(WEAPON_SHOTGUN, Remove);
pChr->GiveWeapon(WEAPON_GRENADE, Remove);
pChr->GiveWeapon(WEAPON_LASER, Remove);
}
else
{
pChr->GiveWeapon(Weapon, Remove);
}
pChr->m_DDRaceState = DDRACE_CHEAT;
}
void CGameContext::Teleport(CCharacter *pChr, vec2 Pos)
{
pChr->Core()->m_Pos = Pos;
pChr->m_Pos = Pos;
pChr->m_PrevPos = Pos;
pChr->m_DDRaceState = DDRACE_CHEAT;
}
void CGameContext::ConToTeleporter(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
unsigned int TeleTo = pResult->GetInteger(0);
CGameControllerDDRace *pGameControllerDDRace = (CGameControllerDDRace *)pSelf->m_pController;
if(!pGameControllerDDRace->m_TeleOuts[TeleTo - 1].empty())
{
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
int TeleOut = pSelf->m_World.m_Core.RandomOr0(pGameControllerDDRace->m_TeleOuts[TeleTo - 1].size());
pSelf->Teleport(pChr, pGameControllerDDRace->m_TeleOuts[TeleTo - 1][TeleOut]);
}
}
}
void CGameContext::ConToCheckTeleporter(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
unsigned int TeleTo = pResult->GetInteger(0);
CGameControllerDDRace *pGameControllerDDRace = (CGameControllerDDRace *)pSelf->m_pController;
if(!pGameControllerDDRace->m_TeleCheckOuts[TeleTo - 1].empty())
{
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientID);
if(pChr)
{
int TeleOut = pSelf->m_World.m_Core.RandomOr0(pGameControllerDDRace->m_TeleCheckOuts[TeleTo - 1].size());
pSelf->Teleport(pChr, pGameControllerDDRace->m_TeleCheckOuts[TeleTo - 1][TeleOut]);
pChr->m_TeleCheckpoint = TeleTo;
}
}
}
void CGameContext::ConTeleport(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Tele = pResult->NumArguments() == 2 ? pResult->GetInteger(0) : pResult->m_ClientID;
int TeleTo = pResult->NumArguments() ? pResult->GetInteger(pResult->NumArguments() - 1) : pResult->m_ClientID;
int AuthLevel = pSelf->Server()->GetAuthedState(pResult->m_ClientID);
if(Tele != pResult->m_ClientID && AuthLevel < g_Config.m_SvTeleOthersAuthLevel)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "tele", "you aren't allowed to tele others");
return;
}
CCharacter *pChr = pSelf->GetPlayerChar(Tele);
if(pChr && pSelf->GetPlayerChar(TeleTo))
{
pSelf->Teleport(pChr, pSelf->m_apPlayers[TeleTo]->m_ViewPos);
}
}
void CGameContext::ConKill(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
if(!pPlayer || (pPlayer->m_LastKill && pPlayer->m_LastKill + pSelf->Server()->TickSpeed() * g_Config.m_SvKillDelay > pSelf->Server()->Tick()))
return;
pPlayer->m_LastKill = pSelf->Server()->Tick();
pPlayer->KillCharacter(WEAPON_SELF);
//pPlayer->m_RespawnTick = pSelf->Server()->Tick() + pSelf->Server()->TickSpeed() * g_Config.m_SvSuicidePenalty;
}
void CGameContext::ConForcePause(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
int Seconds = 0;
if(pResult->NumArguments() > 1)
Seconds = clamp(pResult->GetInteger(1), 0, 360);
CPlayer *pPlayer = pSelf->m_apPlayers[Victim];
if(!pPlayer)
return;
pPlayer->ForcePause(Seconds);
}
bool CGameContext::TryVoteMute(const NETADDR *pAddr, int Secs, const char *pReason)
{
// find a matching vote mute for this ip, update expiration time if found
for(int i = 0; i < m_NumVoteMutes; i++)
{
if(net_addr_comp_noport(&m_aVoteMutes[i].m_Addr, pAddr) == 0)
{
m_aVoteMutes[i].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed();
str_copy(m_aVoteMutes[i].m_aReason, pReason, sizeof(m_aVoteMutes[i].m_aReason));
return true;
}
}
// nothing to update create new one
if(m_NumVoteMutes < MAX_VOTE_MUTES)
{
m_aVoteMutes[m_NumVoteMutes].m_Addr = *pAddr;
m_aVoteMutes[m_NumVoteMutes].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed();
str_copy(m_aVoteMutes[m_NumVoteMutes].m_aReason, pReason, sizeof(m_aVoteMutes[m_NumVoteMutes].m_aReason));
m_NumVoteMutes++;
return true;
}
// no free slot found
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemute", "vote mute array is full");
return false;
}
void CGameContext::VoteMute(const NETADDR *pAddr, int Secs, const char *pReason, const char *pDisplayName, int AuthedID)
{
if(!TryVoteMute(pAddr, Secs, pReason))
return;
if(!pDisplayName)
return;
char aBuf[128];
if(pReason[0])
str_format(aBuf, sizeof aBuf, "'%s' banned '%s' for %d seconds from voting (%s)",
Server()->ClientName(AuthedID), pDisplayName, Secs, pReason);
else
str_format(aBuf, sizeof aBuf, "'%s' banned '%s' for %d seconds from voting",
Server()->ClientName(AuthedID), pDisplayName, Secs);
SendChat(-1, CHAT_ALL, aBuf);
}
bool CGameContext::VoteUnmute(const NETADDR *pAddr, const char *pDisplayName, int AuthedID)
{
for(int i = 0; i < m_NumVoteMutes; i++)
{
if(net_addr_comp_noport(&m_aVoteMutes[i].m_Addr, pAddr) == 0)
{
m_NumVoteMutes--;
m_aVoteMutes[i] = m_aVoteMutes[m_NumVoteMutes];
if(pDisplayName)
{
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' unbanned '%s' from voting.",
Server()->ClientName(AuthedID), pDisplayName);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "voteunmute", aBuf);
}
return true;
}
}
return false;
}
bool CGameContext::TryMute(const NETADDR *pAddr, int Secs, const char *pReason, bool InitialChatDelay)
{
// find a matching mute for this ip, update expiration time if found
for(int i = 0; i < m_NumMutes; i++)
{
if(net_addr_comp_noport(&m_aMutes[i].m_Addr, pAddr) == 0)
{
const int NewExpire = Server()->Tick() + Secs * Server()->TickSpeed();
if(NewExpire > m_aMutes[i].m_Expire)
{
m_aMutes[i].m_Expire = NewExpire;
str_copy(m_aMutes[i].m_aReason, pReason, sizeof(m_aMutes[i].m_aReason));
m_aMutes[i].m_InitialChatDelay = InitialChatDelay;
}
return true;
}
}
// nothing to update create new one
if(m_NumMutes < MAX_MUTES)
{
m_aMutes[m_NumMutes].m_Addr = *pAddr;
m_aMutes[m_NumMutes].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed();
str_copy(m_aMutes[m_NumMutes].m_aReason, pReason, sizeof(m_aMutes[m_NumMutes].m_aReason));
m_aMutes[m_NumMutes].m_InitialChatDelay = InitialChatDelay;
m_NumMutes++;
return true;
}
// no free slot found
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", "mute array is full");
return false;
}
void CGameContext::Mute(const NETADDR *pAddr, int Secs, const char *pDisplayName, const char *pReason, bool InitialChatDelay)
{
if(Secs <= 0)
return;
if(!TryMute(pAddr, Secs, pReason, InitialChatDelay))
return;
if(InitialChatDelay)
return;
if(!pDisplayName)
return;
char aBuf[128];
if(pReason[0])
str_format(aBuf, sizeof aBuf, "'%s' has been muted for %d seconds (%s)", pDisplayName, Secs, pReason);
else
str_format(aBuf, sizeof aBuf, "'%s' has been muted for %d seconds", pDisplayName, Secs);
SendChat(-1, CHAT_ALL, aBuf);
}
void CGameContext::ConVoteMute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemute", "Client ID not found");
return;
}
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
int Seconds = clamp(pResult->GetInteger(1), 1, 86400);
const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(2) : "";
pSelf->VoteMute(&Addr, Seconds, pReason, pSelf->Server()->ClientName(Victim), pResult->m_ClientID);
}
void CGameContext::ConVoteUnmute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "voteunmute", "Client ID not found");
return;
}
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
bool Found = pSelf->VoteUnmute(&Addr, pSelf->Server()->ClientName(Victim), pResult->m_ClientID);
if(Found)
{
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' unbanned '%s' from voting.",
pSelf->Server()->ClientName(pResult->m_ClientID), pSelf->Server()->ClientName(Victim));
pSelf->SendChat(-1, 0, aBuf);
}
}
void CGameContext::ConVoteMutes(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(pSelf->m_NumVoteMutes <= 0)
{
// Just to make sure.
pSelf->m_NumVoteMutes = 0;
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemutes",
"There are no active vote mutes.");
return;
}
char aIpBuf[64];
char aBuf[128];
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemutes",
"Active vote mutes:");
for(int i = 0; i < pSelf->m_NumVoteMutes; i++)
{
net_addr_str(&pSelf->m_aVoteMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof aBuf, "%d: \"%s\", %d seconds left (%s)", i,
aIpBuf, (pSelf->m_aVoteMutes[i].m_Expire - pSelf->Server()->Tick()) / pSelf->Server()->TickSpeed(), pSelf->m_aVoteMutes[i].m_aReason);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "votemutes", aBuf);
}
}
void CGameContext::ConMute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->Console()->Print(
IConsole::OUTPUT_LEVEL_STANDARD,
"mutes",
"Use either 'muteid <client_id> <seconds> <reason>' or 'muteip <ip> <seconds> <reason>'");
}
// mute through client id
void CGameContext::ConMuteID(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "muteid", "Client id not found.");
return;
}
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(2) : "";
pSelf->Mute(&Addr, clamp(pResult->GetInteger(1), 1, 86400),
pSelf->Server()->ClientName(Victim), pReason);
}
// mute through ip, arguments reversed to workaround parsing
void CGameContext::ConMuteIP(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
NETADDR Addr;
if(net_addr_from_str(&Addr, pResult->GetString(0)))
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes",
"Invalid network address to mute");
}
const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(2) : "";
pSelf->Mute(&Addr, clamp(pResult->GetInteger(1), 1, 86400), NULL, pReason);
}
// unmute by mute list index
void CGameContext::ConUnmute(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Index = pResult->GetInteger(0);
if(Index < 0 || Index >= pSelf->m_NumMutes)
return;
char aIpBuf[64];
char aBuf[64];
net_addr_str(&pSelf->m_aMutes[Index].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof(aBuf), "Unmuted %s", aIpBuf);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", aBuf);
pSelf->m_NumMutes--;
pSelf->m_aMutes[Index] = pSelf->m_aMutes[pSelf->m_NumMutes];
}
// unmute by player id
void CGameContext::ConUnmuteID(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim])
return;
NETADDR Addr;
pSelf->Server()->GetClientAddr(Victim, &Addr);
for(int i = 0; i < pSelf->m_NumMutes; i++)
{
if(net_addr_comp_noport(&pSelf->m_aMutes[i].m_Addr, &Addr) == 0)
{
char aIpBuf[64];
char aBuf[64];
net_addr_str(&pSelf->m_aMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof(aBuf), "Unmuted %s", aIpBuf);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", aBuf);
pSelf->m_NumMutes--;
pSelf->m_aMutes[i] = pSelf->m_aMutes[pSelf->m_NumMutes];
return;
}
}
}
// list mutes
void CGameContext::ConMutes(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(pSelf->m_NumMutes <= 0)
{
// Just to make sure.
pSelf->m_NumMutes = 0;
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes",
"There are no active mutes.");
return;
}
char aIpBuf[64];
char aBuf[128];
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes",
"Active mutes:");
for(int i = 0; i < pSelf->m_NumMutes; i++)
{
net_addr_str(&pSelf->m_aMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof aBuf, "%d: \"%s\", %d seconds left (%s)", i, aIpBuf,
(pSelf->m_aMutes[i].m_Expire - pSelf->Server()->Tick()) / pSelf->Server()->TickSpeed(), pSelf->m_aMutes[i].m_aReason);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", aBuf);
}
}
void CGameContext::ConModerate(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!CheckClientID(pResult->m_ClientID))
return;
bool HadModerator = pSelf->PlayerModerating();
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
pPlayer->m_Moderating = !pPlayer->m_Moderating;
char aBuf[256];
if(!HadModerator && pPlayer->m_Moderating)
str_format(aBuf, sizeof(aBuf), "Server kick/spec votes will now be actively moderated.");
if(!pSelf->PlayerModerating())
str_format(aBuf, sizeof(aBuf), "Server kick/spec votes are no longer actively moderated.");
pSelf->SendChat(-1, CHAT_ALL, aBuf, 0);
if(pPlayer->m_Moderating)
pSelf->SendChatTarget(pResult->m_ClientID, "Active moderator mode enabled for you.");
else
pSelf->SendChatTarget(pResult->m_ClientID, "Active moderator mode disabled for you.");
}
void CGameContext::ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController;
if(g_Config.m_SvTeam == SV_TEAM_FORBIDDEN || g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "join",
"Teams are disabled");
return;
}
int Target = pResult->GetVictim();
int Team = pResult->GetInteger(1);
if(Team < TEAM_FLOCK || Team >= TEAM_SUPER)
return;
CCharacter *pChr = pSelf->GetPlayerChar(Target);
if((pController->m_Teams.m_Core.Team(Target) && pController->m_Teams.GetDDRaceState(pSelf->m_apPlayers[Target]) == DDRACE_STARTED) || (pChr && pController->m_Teams.IsPractice(pChr->Team())))
pSelf->m_apPlayers[Target]->KillCharacter(WEAPON_GAME);
pController->m_Teams.SetForceCharacterTeam(Target, Team);
}
void CGameContext::ConUninvite(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController;
pController->m_Teams.SetClientInvited(pResult->GetInteger(1), pResult->GetVictim(), false);
}
void CGameContext::ConFreezeHammer(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
CCharacter *pChr = pSelf->GetPlayerChar(Victim);
if(!pChr)
return;
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' got freeze hammer!",
pSelf->Server()->ClientName(Victim));
pSelf->SendChat(-1, CHAT_ALL, aBuf);
pChr->m_FreezeHammer = true;
}
void CGameContext::ConUnFreezeHammer(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int Victim = pResult->GetVictim();
CCharacter *pChr = pSelf->GetPlayerChar(Victim);
if(!pChr)
return;
char aBuf[128];
str_format(aBuf, sizeof aBuf, "'%s' lost freeze hammer!",
pSelf->Server()->ClientName(Victim));
pSelf->SendChat(-1, CHAT_ALL, aBuf);
pChr->m_FreezeHammer = false;
}
void CGameContext::ConVoteNo(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->ForceVote(pResult->m_ClientID, false);
}
void CGameContext::ConDrySave(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
if(!pPlayer || pSelf->Server()->GetAuthedState(pResult->m_ClientID) != AUTHED_ADMIN)
return;
CSaveTeam SavedTeam(pSelf->m_pController);
int Result = SavedTeam.Save(pPlayer->GetTeam());
if(CSaveTeam::HandleSaveError(Result, pResult->m_ClientID, pSelf))
return;
char aTimestamp[32];
str_timestamp(aTimestamp, sizeof(aTimestamp));
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%s_%s_%s.save", pSelf->Server()->GetMapName(), aTimestamp, pSelf->Server()->GetAuthName(pResult->m_ClientID));
IOHANDLE File = pSelf->Storage()->OpenFile(aBuf, IOFLAG_WRITE, IStorage::TYPE_ALL);
if(!File)
return;
int Len = str_length(SavedTeam.GetString());
io_write(File, SavedTeam.GetString(), Len);
io_close(File);
}
void CGameContext::ConDumpAntibot(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->Antibot()->Dump();
}
void CGameContext::ConDumpLog(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
int LimitSecs = MAX_LOG_SECONDS;
if(pResult->NumArguments() > 0)
LimitSecs = pResult->GetInteger(0);
if(LimitSecs < 0)
return;
for(int i = pSelf->m_FirstLog; i != pSelf->m_LastLog; i = (i + 1) % pSelf->MAX_LOGS)
{
CLog *pEntry = &pSelf->m_aLogs[i];
if(!pEntry->m_Timestamp)
continue;
int Seconds = (time_get() - pEntry->m_Timestamp) / time_freq();
if(Seconds > LimitSecs)
continue;
char aBuf[256];
if(pEntry->m_FromServer)
str_format(aBuf, sizeof aBuf, "%s, %d seconds ago", pEntry->m_aDescription, Seconds);
else
str_format(aBuf, sizeof aBuf, "%s, %d seconds ago < addr=<{%s}> name='%s' client=%d",
pEntry->m_aDescription, Seconds, pEntry->m_aClientAddrStr, pEntry->m_aClientName, pEntry->m_ClientVersion);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "log", aBuf);
}
}
void CGameContext::LogEvent(const char *Description, int ClientID)
{
CLog *pNewEntry = &m_aLogs[m_LastLog];
m_LastLog = (m_LastLog + 1) % MAX_LOGS;
if(m_LastLog == m_FirstLog)
m_FirstLog++;
pNewEntry->m_Timestamp = time_get();
str_copy(pNewEntry->m_aDescription, Description);
pNewEntry->m_FromServer = ClientID < 0;
if(!pNewEntry->m_FromServer)
{
pNewEntry->m_ClientVersion = Server()->GetClientVersion(ClientID);
Server()->GetClientAddr(ClientID, pNewEntry->m_aClientAddrStr, sizeof(pNewEntry->m_aClientAddrStr));
str_copy(pNewEntry->m_aClientName, Server()->ClientName(ClientID));
}
}