diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 245c850246c..230c3a4589d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -92,7 +92,7 @@ jobs: brew update || true brew install pkg-config sdl2 ffmpeg ninja molten-vk vulkan-headers glslang spirv-tools || true # --overwrite for: Target /usr/local/bin/2to3 already exists. - brew link --overwrite python@3.10 + brew link --overwrite python@3.11 brew upgrade freetype pip3 install dmgbuild echo /Library/Frameworks/Python.framework/Versions/3.11/bin >> $GITHUB_PATH @@ -140,18 +140,16 @@ jobs: run: | mkdir headless cd headless - CFLAGS="$CFLAGS --coverage" - CXXFLAGS="$CXXFLAGS --coverage" - LDFLAGS="$LDFLAGS --coverage" ${{ matrix.cmake-path }}cmake --version - ${{ matrix.cmake-path }}cmake -E env ${{ matrix.cmake-init-env }} ${{ matrix.cmake-path }}cmake ${{ matrix.cmake-args }} -DHEADLESS_CLIENT=ON -DCMAKE_BUILD_TYPE=Debug -Werror=dev -DDOWNLOAD_GTEST=ON -DDEV=ON -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG=. .. - ${{ matrix.cmake-path }}cmake --build . --config Debug ${{ matrix.build-args }} + ${{ matrix.cmake-path }}cmake -E env CXXFLAGS="--coverage -Werror" ${{ matrix.cmake-path }}cmake -E env LDFLAGS="--coverage -Werror" ${{ matrix.cmake-path }}cmake ${{ matrix.cmake-args }} -DHEADLESS_CLIENT=ON -DCMAKE_BUILD_TYPE=Debug -Werror=dev -DDOWNLOAD_GTEST=ON -DDEV=ON -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG=. .. + ${{ matrix.cmake-path }}cmake -E env RUSTFLAGS="-Clink-arg=--coverage" ${{ matrix.cmake-path }}cmake --build . --config Debug ${{ matrix.build-args }} mv chillerbot-ux DDNet || true + - name: Test headless client (unit tests) if: contains(matrix.os, 'ubuntu-latest') run: | cd headless - ${{ matrix.cmake-path }}cmake --build . --config Debug --target run_tests ${{ matrix.build-args }} + ${{ matrix.cmake-path }}cmake -E env RUSTFLAGS="-Clink-arg=--coverage" RUSTDOCFLAGS="-Clink-arg=--coverage" ${{ matrix.cmake-path }}cmake --build . --config Debug --target run_tests ${{ matrix.build-args }} - name: Upload Codecov report (unit tests) if: contains(matrix.os, 'ubuntu-latest') @@ -212,7 +210,7 @@ jobs: with: gcov: true gcov_include: src - flags: intgrationtests + flags: integrationtests - name: Package run: | diff --git a/.gitignore b/.gitignore index 5c66c591875..87fab6a91a5 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ chillpw_* config_retrieve config_store crapnet +demo_extract_chat dilate dummy_map fake_server diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b555d8fb5a..9954a66ab57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,6 +330,8 @@ if(NOT MSVC AND NOT HAIKU) add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wthread-safety) add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wthread-safety-negative) add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wsuggest-override) + add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wdynamic-class-memaccess) # clang + add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wclass-memaccess) # gcc add_linker_flag_if_supported(OUR_FLAGS_LINK -Wno-alloc-size-larger-than) # save.cpp with LTO # add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wdouble-promotion) # Many occurrences # add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN -Wnull-dereference) # Many occurrences @@ -2623,6 +2625,8 @@ if(SERVER) gamecontroller.h gamemodes/DDRace.cpp gamemodes/DDRace.h + gamemodes/mod.cpp + gamemodes/mod.h gameworld.cpp gameworld.h player.cpp @@ -2837,6 +2841,7 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST) linereader.cpp mapbugs.cpp math.cpp + memory.cpp name_ban.cpp net.cpp netaddr.cpp diff --git a/codecov.yml b/codecov.yml index 69cb76019a4..00bb737403e 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1 +1,11 @@ comment: false +github_checks: + annotations: false +coverage: + status: + project: + default: + target: 0% + patch: + default: + target: 0% diff --git a/src/antibot/antibot_data.h b/src/antibot/antibot_data.h index cfc6d40b2cd..ea244aa194a 100644 --- a/src/antibot/antibot_data.h +++ b/src/antibot/antibot_data.h @@ -6,7 +6,7 @@ enum { - ANTIBOT_ABI_VERSION = 7, + ANTIBOT_ABI_VERSION = 9, ANTIBOT_MSGFLAG_NONVITAL = 1, ANTIBOT_MSGFLAG_FLUSH = 2, @@ -88,6 +88,7 @@ struct CAntibotData int64_t m_Now; int64_t m_Freq; + void (*m_pfnKick)(int ClientID, const char *pMessage, void *pUser); void (*m_pfnLog)(const char *pMessage, void *pUser); void (*m_pfnReport)(int ClientID, const char *pMessage, void *pUser); void (*m_pfnSend)(int ClientID, const void *pData, int DataSize, int Flags, void *pUser); diff --git a/src/antibot/antibot_interface.h b/src/antibot/antibot_interface.h index b89220a089d..a982802c9e0 100644 --- a/src/antibot/antibot_interface.h +++ b/src/antibot/antibot_interface.h @@ -16,7 +16,7 @@ ANTIBOTAPI void AntibotRoundStart(CAntibotRoundData *pRoundData); ANTIBOTAPI void AntibotRoundEnd(void); ANTIBOTAPI void AntibotUpdateData(void); ANTIBOTAPI void AntibotDestroy(void); -ANTIBOTAPI void AntibotDump(void); +ANTIBOTAPI void AntibotConsoleCommand(const char *pCommand); ANTIBOTAPI void AntibotOnPlayerInit(int ClientID); ANTIBOTAPI void AntibotOnPlayerDestroy(int ClientID); ANTIBOTAPI void AntibotOnSpawn(int ClientID); diff --git a/src/antibot/antibot_null.cpp b/src/antibot/antibot_null.cpp index f343937c765..6a70c0387a1 100644 --- a/src/antibot/antibot_null.cpp +++ b/src/antibot/antibot_null.cpp @@ -2,6 +2,8 @@ #include "antibot_interface.h" +#include + static CAntibotData *g_pData; extern "C" { @@ -19,9 +21,16 @@ void AntibotRoundStart(CAntibotRoundData *pRoundData){}; void AntibotRoundEnd(void){}; void AntibotUpdateData(void) {} void AntibotDestroy(void) { g_pData = 0; } -void AntibotDump(void) +void AntibotConsoleCommand(const char *pCommand) { - g_pData->m_pfnLog("null antibot", g_pData->m_pUser); + if(strcmp(pCommand, "dump") == 0) + { + g_pData->m_pfnLog("null antibot", g_pData->m_pUser); + } + else + { + g_pData->m_pfnLog("unknown command", g_pData->m_pUser); + } } void AntibotOnPlayerInit(int /*ClientID*/) {} void AntibotOnPlayerDestroy(int /*ClientID*/) {} diff --git a/src/base/system.cpp b/src/base/system.cpp index a484ca3de05..2ee017ed1a0 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -245,11 +245,6 @@ void mem_move(void *dest, const void *source, size_t size) memmove(dest, source, size); } -void mem_zero(void *block, size_t size) -{ - memset(block, 0, size); -} - int mem_comp(const void *a, const void *b, size_t size) { return memcmp(a, b, size); diff --git a/src/base/system.h b/src/base/system.h index 702373160c4..3f970115597 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -171,7 +172,12 @@ void mem_move(void *dest, const void *source, size_t size); * @param block Pointer to the block to zero out. * @param size Size of the block. */ -void mem_zero(void *block, size_t size); +template +inline void mem_zero(T *block, size_t size) +{ + static_assert((std::is_trivially_constructible::value && std::is_trivially_destructible::value) || std::is_fundamental::value); + memset(block, 0, size); +} /** * Compares two blocks of memory @@ -2835,7 +2841,7 @@ bool shell_unregister_application(const char *executable, bool *updated); * Notifies the system that a protocol or file extension has been changed and the shell needs to be updated. * * @ingroup Shell - * + * * @remark This is a potentially expensive operation, so it should only be called when necessary. */ void shell_update(); diff --git a/src/base/vmath.h b/src/base/vmath.h index 6797e5db1d9..b83a1ae025f 100644 --- a/src/base/vmath.h +++ b/src/base/vmath.h @@ -23,11 +23,7 @@ class vector2_base T y, v; }; - constexpr vector2_base() : - x(T()), y(T()) - { - } - + constexpr vector2_base() = default; constexpr vector2_base(T nx, T ny) : x(nx), y(ny) { @@ -198,11 +194,7 @@ class vector3_base T z, b, l, w; }; - constexpr vector3_base() : - x(T()), y(T()), z(T()) - { - } - + constexpr vector3_base() = default; constexpr vector3_base(T nx, T ny, T nz) : x(nx), y(ny), z(nz) { @@ -326,11 +318,7 @@ class vector4_base T w, a; }; - constexpr vector4_base() : - x(T()), y(T()), z(T()), w(T()) - { - } - + constexpr vector4_base() = default; constexpr vector4_base(T nx, T ny, T nz, T nw) : x(nx), y(ny), z(nz), w(nw) { diff --git a/src/engine/antibot.h b/src/engine/antibot.h index 34827e53cc0..bf8e208c4a9 100644 --- a/src/engine/antibot.h +++ b/src/engine/antibot.h @@ -22,7 +22,7 @@ class IAntibot : public IInterface virtual void OnHookAttach(int ClientID, bool Player) = 0; // Commands - virtual void Dump() = 0; + virtual void ConsoleCommand(const char *pCommand) = 0; virtual ~IAntibot(){}; }; diff --git a/src/engine/client.h b/src/engine/client.h index 9aca4aaf82e..c853ccb0d80 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -87,14 +87,11 @@ class IClient : public IInterface float m_GlobalTime; float m_RenderFrameTime; - int m_GameTickSpeed; - float m_FrameTimeAvg; TMapLoadingCallbackFunc m_MapLoadingCBFunc; char m_aNews[3000]; - char m_aCommunityIconsDownloadUrl[256]; int m_Points; int64_t m_ReconnectTime; @@ -142,7 +139,7 @@ class IClient : public IInterface inline float PredIntraGameTick(int Conn) const { return m_aPredIntraTick[Conn]; } inline float IntraGameTickSincePrev(int Conn) const { return m_aGameIntraTickSincePrev[Conn]; } inline float GameTickTime(int Conn) const { return m_aGameTickTime[Conn]; } - inline int GameTickSpeed() const { return m_GameTickSpeed; } + inline int GameTickSpeed() const { return SERVER_TICK_SPEED; } // other time access inline float RenderFrameTime() const { return m_RenderFrameTime; } @@ -258,7 +255,6 @@ class IClient : public IInterface virtual unsigned GetCurrentMapCrc() const = 0; const char *News() const { return m_aNews; } - const char *CommunityIconsDownloadUrl() const { return m_aCommunityIconsDownloadUrl; } int Points() const { return m_Points; } int64_t ReconnectTime() const { return m_ReconnectTime; } void SetReconnectTime(int64_t ReconnectTime) { m_ReconnectTime = ReconnectTime; } diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 36e8d6e3403..e3feac8ea92 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -85,8 +85,6 @@ CClient::CClient() : m_RenderFrameTime = 0.0001f; m_LastRenderTime = time_get(); - m_GameTickSpeed = SERVER_TICK_SPEED; - m_SnapCrcErrors = 0; m_AutoScreenshotRecycle = false; m_AutoStatScreenshotRecycle = false; @@ -137,7 +135,6 @@ CClient::CClient() : m_pDDNetInfoTask = NULL; m_aNews[0] = '\0'; m_aMapDownloadUrl[0] = '\0'; - m_aCommunityIconsDownloadUrl[0] = '\0'; m_Points = -1; m_CurrentServerInfoRequestTime = -1; @@ -348,7 +345,7 @@ void CClient::Rcon(const char *pCmd) bool CClient::ConnectionProblems() const { - return m_aNetClient[g_Config.m_ClDummy].GotProblems(MaxLatencyTicks() * time_freq() / SERVER_TICK_SPEED) != 0; + return m_aNetClient[g_Config.m_ClDummy].GotProblems(MaxLatencyTicks() * time_freq() / GameTickSpeed()) != 0; } void CClient::DirectInput(int *pInput, int Size) @@ -392,7 +389,7 @@ void CClient::SendInput() m_aInputs[i][m_aCurrentInput[i]].m_Tick = m_aPredTick[g_Config.m_ClDummy]; m_aInputs[i][m_aCurrentInput[i]].m_PredictedTime = m_PredictedTime.Get(Now); - m_aInputs[i][m_aCurrentInput[i]].m_PredictionMargin = m_PredictedTime.GetMargin(Now); + m_aInputs[i][m_aCurrentInput[i]].m_PredictionMargin = PredictionMargin() * time_freq() / 1000; m_aInputs[i][m_aCurrentInput[i]].m_Time = Now; // pack it @@ -789,7 +786,7 @@ int CClient::GetCurrentRaceTime() { if(GameClient()->GetLastRaceTick() < 0) return 0; - return (GameTick(g_Config.m_ClDummy) - GameClient()->GetLastRaceTick()) / 50; + return (GameTick(g_Config.m_ClDummy) - GameClient()->GetLastRaceTick()) / GameTickSpeed(); } void CClient::GetServerInfo(CServerInfo *pServerInfo) const @@ -1756,7 +1753,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) if(m_aInputs[Conn][k].m_Tick == InputPredTick) { Target = m_aInputs[Conn][k].m_PredictedTime + (Now - m_aInputs[Conn][k].m_Time); - Target = Target - (int64_t)((TimeLeft / 1000.0f) * time_freq()) + m_aInputs[Conn][k].m_PredictionMargin; + Target = Target - (int64_t)((TimeLeft / 1000.0f) * time_freq()); break; } } @@ -1950,11 +1947,11 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) // start at 200ms and work from there if(!Dummy) { - m_PredictedTime.Init(GameTick * time_freq() / 50); + m_PredictedTime.Init(GameTick * time_freq() / GameTickSpeed()); m_PredictedTime.SetAdjustSpeed(CSmoothTime::ADJUSTDIRECTION_UP, 1000.0f); m_PredictedTime.UpdateMargin(PredictionMargin() * time_freq() / 1000); } - m_aGameTime[Conn].Init((GameTick - 1) * time_freq() / 50); + m_aGameTime[Conn].Init((GameTick - 1) * time_freq() / GameTickSpeed()); m_aapSnapshots[Conn][SNAP_PREV] = m_aSnapshotStorage[Conn].m_pFirst; m_aapSnapshots[Conn][SNAP_CURRENT] = m_aSnapshotStorage[Conn].m_pLast; if(!Dummy) @@ -1976,12 +1973,12 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) if(m_aReceivedSnapshots[Conn] > 2) { int64_t Now = m_aGameTime[Conn].Get(time_get()); - int64_t TickStart = GameTick * time_freq() / 50; + int64_t TickStart = GameTick * time_freq() / GameTickSpeed(); int64_t TimeLeft = (TickStart - Now) * 1000 / time_freq(); - m_aGameTime[Conn].Update(&m_GametimeMarginGraph, (GameTick - 1) * time_freq() / 50, TimeLeft, CSmoothTime::ADJUSTDIRECTION_DOWN); + m_aGameTime[Conn].Update(&m_GametimeMarginGraph, (GameTick - 1) * time_freq() / GameTickSpeed(), TimeLeft, CSmoothTime::ADJUSTDIRECTION_DOWN); } - if(m_aReceivedSnapshots[Conn] > 50 && !m_aCodeRunAfterJoin[Conn]) + if(m_aReceivedSnapshots[Conn] > GameTickSpeed() && !m_aCodeRunAfterJoin[Conn]) { if(m_ServerCapabilities.m_ChatTimeoutCode) { @@ -2290,12 +2287,6 @@ void CClient::LoadDDNetInfo() str_copy(m_aMapDownloadUrl, MapDownloadUrl); } - const json_value &CommunityIconsDownloadUrl = DDNetInfo["community-icons-download-url"]; - if(CommunityIconsDownloadUrl.type == json_string) - { - str_copy(m_aCommunityIconsDownloadUrl, CommunityIconsDownloadUrl); - } - const json_value &Points = DDNetInfo["points"]; if(Points.type == json_integer) { @@ -2518,7 +2509,7 @@ void CClient::Update() while(true) { CSnapshotStorage::CHolder *pCur = m_aapSnapshots[!g_Config.m_ClDummy][SNAP_CURRENT]; - int64_t TickStart = (pCur->m_Tick) * time_freq() / 50; + int64_t TickStart = (pCur->m_Tick) * time_freq() / GameTickSpeed(); if(TickStart < Now) { @@ -2557,7 +2548,7 @@ void CClient::Update() while(true) { CSnapshotStorage::CHolder *pCur = m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT]; - int64_t TickStart = (pCur->m_Tick) * time_freq() / 50; + int64_t TickStart = (pCur->m_Tick) * time_freq() / GameTickSpeed(); if(TickStart < Now) { @@ -2586,23 +2577,23 @@ void CClient::Update() if(m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT] && m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]) { - int64_t CurTickStart = m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT]->m_Tick * time_freq() / SERVER_TICK_SPEED; - int64_t PrevTickStart = m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]->m_Tick * time_freq() / SERVER_TICK_SPEED; - int PrevPredTick = (int)(PredNow * SERVER_TICK_SPEED / time_freq()); + int64_t CurTickStart = m_aapSnapshots[g_Config.m_ClDummy][SNAP_CURRENT]->m_Tick * time_freq() / GameTickSpeed(); + int64_t PrevTickStart = m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]->m_Tick * time_freq() / GameTickSpeed(); + int PrevPredTick = (int)(PredNow * GameTickSpeed() / time_freq()); int NewPredTick = PrevPredTick + 1; m_aGameIntraTick[g_Config.m_ClDummy] = (Now - PrevTickStart) / (float)(CurTickStart - PrevTickStart); m_aGameTickTime[g_Config.m_ClDummy] = (Now - PrevTickStart) / (float)time_freq(); - m_aGameIntraTickSincePrev[g_Config.m_ClDummy] = (Now - PrevTickStart) / (float)(time_freq() / SERVER_TICK_SPEED); + m_aGameIntraTickSincePrev[g_Config.m_ClDummy] = (Now - PrevTickStart) / (float)(time_freq() / GameTickSpeed()); - int64_t CurPredTickStart = NewPredTick * time_freq() / SERVER_TICK_SPEED; - int64_t PrevPredTickStart = PrevPredTick * time_freq() / SERVER_TICK_SPEED; + int64_t CurPredTickStart = NewPredTick * time_freq() / GameTickSpeed(); + int64_t PrevPredTickStart = PrevPredTick * time_freq() / GameTickSpeed(); m_aPredIntraTick[g_Config.m_ClDummy] = (PredNow - PrevPredTickStart) / (float)(CurPredTickStart - PrevPredTickStart); if(absolute(NewPredTick - m_aapSnapshots[g_Config.m_ClDummy][SNAP_PREV]->m_Tick) > MaxLatencyTicks()) { m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", "prediction time reset!"); - m_PredictedTime.Init(CurTickStart + 2 * time_freq() / SERVER_TICK_SPEED); + m_PredictedTime.Init(CurTickStart + 2 * time_freq() / GameTickSpeed()); } if(NewPredTick > m_aPredTick[g_Config.m_ClDummy]) @@ -4248,9 +4239,7 @@ void CClient::RegisterCommands() static CClient *CreateClient() { - CClient *pClient = static_cast(malloc(sizeof(*pClient))); - mem_zero(pClient, sizeof(CClient)); - return new(pClient) CClient; + return new CClient; } void CClient::HandleConnectAddress(const NETADDR *pAddr) @@ -4422,8 +4411,7 @@ int main(int argc, const char **argv) CleanerFunctions.emplace([pKernel, pClient]() { pKernel->Shutdown(); delete pKernel; - pClient->~CClient(); - free(pClient); + delete pClient; }); const std::thread::id MainThreadId = std::this_thread::get_id(); @@ -4721,8 +4709,8 @@ void CClient::GetSmoothTick(int *pSmoothTick, float *pSmoothIntraTick, float Mix int64_t PredTime = m_PredictedTime.Get(time_get()); int64_t SmoothTime = clamp(GameTime + (int64_t)(MixAmount * (PredTime - GameTime)), GameTime, PredTime); - *pSmoothTick = (int)(SmoothTime * 50 / time_freq()) + 1; - *pSmoothIntraTick = (SmoothTime - (*pSmoothTick - 1) * time_freq() / 50) / (float)(time_freq() / 50); + *pSmoothTick = (int)(SmoothTime * GameTickSpeed() / time_freq()) + 1; + *pSmoothIntraTick = (SmoothTime - (*pSmoothTick - 1) * time_freq() / GameTickSpeed()) / (float)(time_freq() / GameTickSpeed()); } void CClient::AddWarning(const SWarning &Warning) @@ -4749,7 +4737,7 @@ SWarning *CClient::GetCurWarning() int CClient::MaxLatencyTicks() const { - return SERVER_TICK_SPEED + (PredictionMargin() * SERVER_TICK_SPEED) / 1000; + return GameTickSpeed() + (PredictionMargin() * GameTickSpeed()) / 1000; } int CClient::PredictionMargin() const diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index f3576253ff2..a293e4a0fc6 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -2,6 +2,7 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include +#include #include #if defined(CONF_FAMILY_UNIX) @@ -551,7 +552,7 @@ bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureID, int x, int return true; } -int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) +bool CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) { char aCompleteFilename[IO_MAX_PATH_LENGTH]; IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType, aCompleteFilename, sizeof(aCompleteFilename)); @@ -574,17 +575,17 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto int PngliteIncompatible; if(::LoadPNG(ImageByteBuffer, pFilename, PngliteIncompatible, pImg->m_Width, pImg->m_Height, pImgBuffer, ImageFormat)) { - pImg->m_pData = pImgBuffer; - - if(ImageFormat == IMAGE_FORMAT_RGB) // ignore_convention + if(ImageFormat == IMAGE_FORMAT_RGB) pImg->m_Format = CImageInfo::FORMAT_RGB; - else if(ImageFormat == IMAGE_FORMAT_RGBA) // ignore_convention + else if(ImageFormat == IMAGE_FORMAT_RGBA) pImg->m_Format = CImageInfo::FORMAT_RGBA; else { free(pImgBuffer); - return 0; + log_error("game/png", "image had unsupported image format. filename='%s' format='%d'", pFilename, (int)ImageFormat); + return false; } + pImg->m_pData = pImgBuffer; if(m_WarnPngliteIncompatibleImages && PngliteIncompatible != 0) { @@ -612,17 +613,17 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto } else { - dbg_msg("game/png", "image had unsupported image format. filename='%s'", pFilename); - return 0; + log_error("game/png", "failed to load file. filename='%s'", pFilename); + return false; } } else { - dbg_msg("game/png", "failed to open file. filename='%s'", pFilename); - return 0; + log_error("game/png", "failed to open file. filename='%s'", pFilename); + return false; } - return 1; + return true; } void CGraphics_Threaded::FreePNG(CImageInfo *pImg) @@ -787,7 +788,6 @@ bool CGraphics_Threaded::ScreenshotDirect() { // add swap command CImageInfo Image; - mem_zero(&Image, sizeof(Image)); bool DidSwap = false; diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 03ca8dba9f2..514680749d9 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -965,7 +965,7 @@ class CGraphics_Threaded : public IEngineGraphics // simple uncompressed RGBA loaders IGraphics::CTextureHandle LoadTexture(const char *pFilename, int StorageType, int Flags = 0) override; - int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) override; + bool LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) override; void FreePNG(CImageInfo *pImg) override; bool CheckImageDivisibility(const char *pFileName, CImageInfo &Img, int DivX, int DivY, bool AllowResize) override; diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 5b99ab19e33..2b649ef5f5d 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -1141,6 +1141,91 @@ void CServerBrowser::LoadDDNetLocation() } } +bool CServerBrowser::ParseCommunityServers(CCommunity *pCommunity, const json_value &Servers) +{ + for(unsigned ServerIndex = 0; ServerIndex < Servers.u.array.length; ++ServerIndex) + { + // pServer - { name, flagId, servers } + const json_value &Server = Servers[ServerIndex]; + if(Server.type != json_object) + { + log_error("serverbrowser", "invalid server (ServerIndex=%u)", ServerIndex); + return false; + } + + const json_value &Name = Server["name"]; + const json_value &FlagId = Server["flagId"]; + const json_value &Types = Server["servers"]; + if(Name.type != json_string || FlagId.type != json_integer || Types.type != json_object) + { + log_error("serverbrowser", "invalid server attribute (ServerIndex=%u)", ServerIndex); + return false; + } + if(Types.u.object.length == 0) + continue; + + pCommunity->m_vCountries.emplace_back(Name.u.string.ptr, FlagId.u.integer); + CCommunityCountry *pCountry = &pCommunity->m_vCountries.back(); + + for(unsigned TypeIndex = 0; TypeIndex < Types.u.object.length; ++TypeIndex) + { + const json_value &Addresses = *Types.u.object.values[TypeIndex].value; + if(Addresses.type != json_array) + { + log_error("serverbrowser", "invalid addresses (ServerIndex=%u, TypeIndex=%u)", ServerIndex, TypeIndex); + return false; + } + if(Addresses.u.array.length == 0) + continue; + + const char *pTypeName = Types.u.object.values[TypeIndex].name; + + // add type if it doesn't exist already + const auto CommunityType = std::find_if(pCommunity->m_vTypes.begin(), pCommunity->m_vTypes.end(), [pTypeName](const auto &Elem) { + return str_comp(Elem.Name(), pTypeName) == 0; + }); + if(CommunityType == pCommunity->m_vTypes.end()) + { + pCommunity->m_vTypes.emplace_back(pTypeName); + } + + // add addresses + for(unsigned AddressIndex = 0; AddressIndex < Addresses.u.array.length; ++AddressIndex) + { + const json_value &Address = Addresses[AddressIndex]; + if(Address.type != json_string) + { + log_error("serverbrowser", "invalid address (ServerIndex=%u, TypeIndex=%u, AddressIndex=%u)", ServerIndex, TypeIndex, AddressIndex); + return false; + } + NETADDR NetAddr; + if(net_addr_from_str(&NetAddr, Address.u.string.ptr)) + { + log_error("serverbrowser", "invalid address (ServerIndex=%u, TypeIndex=%u, AddressIndex=%u)", ServerIndex, TypeIndex, AddressIndex); + continue; + } + pCountry->m_vServers.emplace_back(NetAddr, pTypeName); + } + } + } + return true; +} + +bool CServerBrowser::ParseCommunityFinishes(CCommunity *pCommunity, const json_value &Finishes) +{ + for(unsigned FinishIndex = 0; FinishIndex < Finishes.u.array.length; ++FinishIndex) + { + const json_value &Finish = Finishes[FinishIndex]; + if(Finish.type != json_string) + { + log_error("serverbrowser", "invalid rank (FinishIndex=%u)", FinishIndex); + return false; + } + pCommunity->m_FinishedMaps.emplace((const char *)Finish); + } + return true; +} + void CServerBrowser::LoadDDNetServers() { // Parse communities @@ -1148,139 +1233,99 @@ void CServerBrowser::LoadDDNetServers() m_CommunityServersByAddr.clear(); if(!m_pDDNetInfo) + { + CleanFilters(); return; + } const json_value &Communities = (*m_pDDNetInfo)["communities"]; - if(Communities.type != json_object) + if(Communities.type != json_array) + { + CleanFilters(); return; + } - for(unsigned CommunityIndex = 0; CommunityIndex < Communities.u.object.length; ++CommunityIndex) + for(unsigned CommunityIndex = 0; CommunityIndex < Communities.u.array.length; ++CommunityIndex) { - const char *pCommunityId = Communities.u.object.values[CommunityIndex].name; - const json_value &Community = *Communities.u.object.values[CommunityIndex].value; + const json_value &Community = Communities[CommunityIndex]; if(Community.type != json_object) { - log_error("serverbrowser", "invalid community (CommunityId=%s)", pCommunityId); + log_error("serverbrowser", "invalid community (CommunityIndex=%d)", (int)CommunityIndex); continue; } - const json_value &Name = Community["name"]; - const json_value &JsonServersKey = Community["servers-key"]; - const json_value &JsonRanksKey = Community["ranks-key"]; - const json_value &IconSha256 = Community["icon-sha256"]; - if(Name.type != json_string || JsonServersKey.type != json_string || JsonRanksKey.type != json_string || IconSha256.type != json_string) + const json_value &Id = Community["id"]; + if(Id.type != json_string) { - log_error("serverbrowser", "invalid community attribute (CommunityId=%s)", pCommunityId); + log_error("serverbrowser", "invalid community id (CommunityIndex=%d)", (int)CommunityIndex); continue; } - SHA256_DIGEST ParsedIconSha256; - if(sha256_from_str(&ParsedIconSha256, IconSha256.u.string.ptr) != 0) + const json_value &Icon = Community["icon"]; + const json_value &IconSha256 = Icon["sha256"]; + const json_value &IconUrl = Icon["url"]; + const json_value &Name = Community["name"]; + const json_value *pFinishes = &Icon["finishes"]; + const json_value *pServers = &Icon["servers"]; + if(pFinishes->type == json_none) { - log_error("serverbrowser", "invalid community icon sha256 (CommunityId=%s)", pCommunityId); - continue; + if(str_comp(Id, COMMUNITY_DDNET) == 0) + { + pFinishes = &(*m_pDDNetInfo)["maps"]; + } } - m_vCommunities.emplace_back(pCommunityId, Name.u.string.ptr, JsonServersKey.u.string.ptr, JsonRanksKey.u.string.ptr, ParsedIconSha256); - } - - // Parse finishes for each community - for(auto &Community : m_vCommunities) - { - if(!Community.HasRanks()) + // Backward compatibility. + if(pServers->type == json_none) + { + if(str_comp(Id, COMMUNITY_DDNET) == 0) + { + pServers = &(*m_pDDNetInfo)["servers"]; + } + else if(str_comp(Id, "kog") == 0) + { + pServers = &(*m_pDDNetInfo)["servers-kog"]; + } + } + if(false || + Icon.type != json_object || + IconSha256.type != json_string || + IconUrl.type != json_string || + Name.type != json_string || + (pFinishes->type != json_array && pFinishes->type != json_none) || + pServers->type != json_array) + { + log_error("serverbrowser", "invalid community attribute (CommunityId=%s)", (const char *)Id); continue; - const json_value &Ranks = (*m_pDDNetInfo)[Community.JsonRanksKey()]; - if(Ranks.type != json_array) + } + SHA256_DIGEST ParsedIconSha256; + if(sha256_from_str(&ParsedIconSha256, IconSha256) != 0) { - log_error("serverbrowser", "invalid community ranks (CommunityId=%s)", Community.Id()); + log_error("serverbrowser", "invalid community icon sha256 (CommunityId=%s)", (const char *)Id); continue; } - - for(unsigned RankIndex = 0; RankIndex < Ranks.u.array.length; ++RankIndex) + CCommunity NewCommunity(Id, Name, ParsedIconSha256, IconUrl); + if(!ParseCommunityServers(&NewCommunity, *pServers)) { - const json_value &Rank = *Ranks.u.array.values[RankIndex]; - if(Rank.type != json_string) - { - log_error("serverbrowser", "invalid rank (RankIndex=%u)", RankIndex); - continue; - } - Community.m_RankedMaps.emplace(Rank.u.string.ptr); + log_error("serverbrowser", "invalid community servers (CommunityId=%s)", NewCommunity.Id()); + continue; } - } - - // parse servers for each community - for(auto &Community : m_vCommunities) - { - const json_value &Servers = (*m_pDDNetInfo)[Community.JsonServersKey()]; - if(Servers.type != json_array) + NewCommunity.m_HasFinishes = pFinishes->type == json_array; + if(NewCommunity.m_HasFinishes && !ParseCommunityFinishes(&NewCommunity, *pFinishes)) { - log_error("serverbrowser", "invalid community servers (CommunityId=%s)", Community.Id()); + log_error("serverbrowser", "invalid community finishes (CommunityId=%s)", NewCommunity.Id()); continue; } - for(unsigned ServerIndex = 0; ServerIndex < Servers.u.array.length; ++ServerIndex) + for(const auto &Country : NewCommunity.Countries()) { - // pServer - { name, flagId, servers } - const json_value &Server = *Servers.u.array.values[ServerIndex]; - if(Server.type != json_object) + for(const auto &Server : Country.Servers()) { - log_error("serverbrowser", "invalid server (ServerIndex=%u)", ServerIndex); - continue; - } - - const json_value &Name = Server["name"]; - const json_value &FlagId = Server["flagId"]; - const json_value &Types = Server["servers"]; - if(Name.type != json_string || FlagId.type != json_integer || Types.type != json_object) - { - log_error("serverbrowser", "invalid server attribute (ServerIndex=%u)", ServerIndex); - continue; - } - if(Types.u.object.length == 0) - continue; - - Community.m_vCountries.emplace_back(Name.u.string.ptr, FlagId.u.integer); - CCommunityCountry *pCountry = &Community.m_vCountries.back(); - - for(unsigned TypeIndex = 0; TypeIndex < Types.u.object.length; ++TypeIndex) - { - const json_value &Addresses = *Types.u.object.values[TypeIndex].value; - if(Addresses.type != json_array) - { - log_error("serverbrowser", "invalid addresses (ServerIndex=%u, TypeIndex=%u)", ServerIndex, TypeIndex); - continue; - } - if(Addresses.u.array.length == 0) - continue; - - const char *pTypeName = Types.u.object.values[TypeIndex].name; - - // add type if it doesn't exist already - const auto CommunityType = std::find_if(Community.m_vTypes.begin(), Community.m_vTypes.end(), [pTypeName](const auto &Elem) { - return str_comp(Elem.Name(), pTypeName) == 0; - }); - if(CommunityType == Community.m_vTypes.end()) - { - Community.m_vTypes.emplace_back(pTypeName); - } - - // add addresses - for(unsigned AddressIndex = 0; AddressIndex < Addresses.u.array.length; ++AddressIndex) - { - const json_value &Address = *Addresses.u.array.values[AddressIndex]; - if(Address.type != json_string) - { - log_error("serverbrowser", "invalid address (ServerIndex=%u, TypeIndex=%u, AddressIndex=%u)", ServerIndex, TypeIndex, AddressIndex); - continue; - } - NETADDR NetAddr; - net_addr_from_str(&NetAddr, Address.u.string.ptr); - pCountry->m_vServers.emplace_back(NetAddr, pTypeName); - m_CommunityServersByAddr.emplace(std::make_pair(NetAddr, CCommunityServer(Community.Id(), pCountry->Name(), pTypeName))); - } + m_CommunityServersByAddr.emplace(Server.Address(), CCommunityServer(NewCommunity.Id(), Country.Name(), Server.TypeName())); } } + m_vCommunities.push_back(std::move(NewCommunity)); } // Add default none community - m_vCommunities.emplace_back(COMMUNITY_NONE, "None", "", "", SHA256_ZEROED); + m_vCommunities.emplace_back(COMMUNITY_NONE, "None", SHA256_ZEROED, ""); // Remove unknown elements from exclude lists CleanFilters(); @@ -1391,10 +1436,10 @@ int CServerBrowser::LoadingProgression() const CServerInfo::ERankState CCommunity::HasRank(const char *pMap) const { - if(!HasRanks() || pMap[0] == '\0') + if(!HasRanks()) return CServerInfo::RANK_UNAVAILABLE; const CCommunityMap Needle(pMap); - return m_RankedMaps.count(Needle) == 0 ? CServerInfo::RANK_UNRANKED : CServerInfo::RANK_RANKED; + return m_FinishedMaps.count(Needle) == 0 ? CServerInfo::RANK_UNRANKED : CServerInfo::RANK_RANKED; } const std::vector &CServerBrowser::Communities() const @@ -1485,6 +1530,7 @@ bool CFilterList::Empty() const void CFilterList::Clean(const std::vector &vpAllowedElements) { + size_t NumFiltered = 0; char aNewList[512]; aNewList[0] = '\0'; @@ -1495,10 +1541,15 @@ void CFilterList::Clean(const std::vector &vpAllowedElements) if(aNewList[0] != '\0') str_append(aNewList, ","); str_append(aNewList, pElement); + ++NumFiltered; } } - str_copy(m_pFilter, aNewList, m_FilterSize); + // Prevent filter that would exclude all allowed elements + if(NumFiltered == vpAllowedElements.size()) + m_pFilter[0] = '\0'; + else + str_copy(m_pFilter, aNewList, m_FilterSize); } void CServerBrowser::CleanFilters() diff --git a/src/engine/client/serverbrowser.h b/src/engine/client/serverbrowser.h index 6e0b63cfb82..854907c910d 100644 --- a/src/engine/client/serverbrowser.h +++ b/src/engine/client/serverbrowser.h @@ -219,6 +219,9 @@ class CServerBrowser : public IServerBrowser void SetInfo(CServerEntry *pEntry, const CServerInfo &Info); void SetLatency(NETADDR Addr, int Latency); + + static bool ParseCommunityFinishes(CCommunity *pCommunity, const json_value &Finishes); + static bool ParseCommunityServers(CCommunity *pCommunity, const json_value &Servers); }; #endif diff --git a/src/engine/client/smooth_time.cpp b/src/engine/client/smooth_time.cpp index 059383b4340..9a9675fe770 100644 --- a/src/engine/client/smooth_time.cpp +++ b/src/engine/client/smooth_time.cpp @@ -12,9 +12,7 @@ void CSmoothTime::Init(int64_t Target) m_Snap = time_get(); m_Current = Target; m_Target = Target; - m_SnapMargin = m_Snap; - m_CurrentMargin = 0; - m_TargetMargin = 0; + m_Margin = 0; m_aAdjustSpeed[ADJUSTDIRECTION_DOWN] = 0.3f; m_aAdjustSpeed[ADJUSTDIRECTION_UP] = 0.3f; } @@ -41,15 +39,15 @@ int64_t CSmoothTime::Get(int64_t Now) const a = 1.0f; int64_t r = c + (int64_t)((t - c) * a); - return r + GetMargin(Now); + return r + m_Margin; } void CSmoothTime::UpdateInt(int64_t Target) { int64_t Now = time_get(); - m_Current = Get(Now) - GetMargin(Now); + m_Current = Get(Now) - m_Margin; m_Snap = Now; - m_Target = Target - GetMargin(Now); + m_Target = Target; } void CSmoothTime::Update(CGraph *pGraph, int64_t Target, int TimeLeft, EAdjustDirection AdjustDirection) @@ -97,20 +95,7 @@ void CSmoothTime::Update(CGraph *pGraph, int64_t Target, int TimeLeft, EAdjustDi UpdateInt(Target); } -int64_t CSmoothTime::GetMargin(int64_t Now) const -{ - int64_t TimePassed = Now - m_SnapMargin; - int64_t Diff = m_TargetMargin - m_CurrentMargin; - - float a = clamp(TimePassed / (float)time_freq(), -1.f, 1.f); - int64_t Lim = maximum((int64_t)(a * absolute(Diff)), 1 + TimePassed / 100); - return m_CurrentMargin + (int64_t)clamp(Diff, -Lim, Lim); -} - -void CSmoothTime::UpdateMargin(int64_t TargetMargin) +void CSmoothTime::UpdateMargin(int64_t Margin) { - int64_t Now = time_get(); - m_CurrentMargin = GetMargin(Now); - m_SnapMargin = Now; - m_TargetMargin = TargetMargin; + m_Margin = Margin; } diff --git a/src/engine/client/smooth_time.h b/src/engine/client/smooth_time.h index 999e729b316..efd41e8c4fe 100644 --- a/src/engine/client/smooth_time.h +++ b/src/engine/client/smooth_time.h @@ -22,10 +22,7 @@ class CSmoothTime int64_t m_Snap; int64_t m_Current; int64_t m_Target; - - int64_t m_SnapMargin; - int64_t m_CurrentMargin; - int64_t m_TargetMargin; + int64_t m_Margin; int m_SpikeCounter; float m_aAdjustSpeed[NUM_ADJUSTDIRECTIONS]; @@ -39,8 +36,7 @@ class CSmoothTime void UpdateInt(int64_t Target); void Update(CGraph *pGraph, int64_t Target, int TimeLeft, EAdjustDirection AdjustDirection); - int64_t GetMargin(int64_t Now) const; - void UpdateMargin(int64_t TargetMargin); + void UpdateMargin(int64_t Margin); }; #endif diff --git a/src/engine/client/updater.cpp b/src/engine/client/updater.cpp index 5cd7eda197f..3a6b6e389b8 100644 --- a/src/engine/client/updater.cpp +++ b/src/engine/client/updater.cpp @@ -200,9 +200,9 @@ bool CUpdater::ReplaceClient() str_format(aPath, sizeof(aPath), "update/%s", m_aClientExecTmp); Success &= m_pStorage->RenameBinaryFile(aPath, PLAT_CLIENT_EXEC); #if !defined(CONF_FAMILY_WINDOWS) - m_pStorage->GetBinaryPath(PLAT_CLIENT_EXEC, aPath, sizeof aPath); + m_pStorage->GetBinaryPath(PLAT_CLIENT_EXEC, aPath, sizeof(aPath)); char aBuf[512]; - str_format(aBuf, sizeof aBuf, "chmod +x %s", aPath); + str_format(aBuf, sizeof(aBuf), "chmod +x %s", aPath); if(system(aBuf)) { dbg_msg("updater", "ERROR: failed to set client executable bit"); @@ -224,9 +224,9 @@ bool CUpdater::ReplaceServer() str_format(aPath, sizeof(aPath), "update/%s", m_aServerExecTmp); Success &= m_pStorage->RenameBinaryFile(aPath, PLAT_SERVER_EXEC); #if !defined(CONF_FAMILY_WINDOWS) - m_pStorage->GetBinaryPath(PLAT_SERVER_EXEC, aPath, sizeof aPath); + m_pStorage->GetBinaryPath(PLAT_SERVER_EXEC, aPath, sizeof(aPath)); char aBuf[512]; - str_format(aBuf, sizeof aBuf, "chmod +x %s", aPath); + str_format(aBuf, sizeof(aBuf), "chmod +x %s", aPath); if(system(aBuf)) { dbg_msg("updater", "ERROR: failed to set server executable bit"); @@ -241,7 +241,7 @@ void CUpdater::ParseUpdate() char aPath[IO_MAX_PATH_LENGTH]; void *pBuf; unsigned Length; - if(!m_pStorage->ReadFile(m_pStorage->GetBinaryPath("update/update.json", aPath, sizeof aPath), IStorage::TYPE_ABSOLUTE, &pBuf, &Length)) + if(!m_pStorage->ReadFile(m_pStorage->GetBinaryPath("update/update.json", aPath, sizeof(aPath)), IStorage::TYPE_ABSOLUTE, &pBuf, &Length)) return; json_value *pVersions = json_parse((json_char *)pBuf, Length); diff --git a/src/engine/gfx/image_loader.cpp b/src/engine/gfx/image_loader.cpp index 76ac23205c6..eefb597cdba 100644 --- a/src/engine/gfx/image_loader.cpp +++ b/src/engine/gfx/image_loader.cpp @@ -59,12 +59,15 @@ static EImageFormat LibPNGGetImageFormat(int ColorChannelCount) { case 1: return IMAGE_FORMAT_R; + case 2: + return IMAGE_FORMAT_RA; case 3: return IMAGE_FORMAT_RGB; case 4: return IMAGE_FORMAT_RGBA; default: - return IMAGE_FORMAT_RGBA; + dbg_assert(false, "ColorChannelCount invalid"); + dbg_break(); } } @@ -276,14 +279,20 @@ static void FlushPNGWrite(png_structp png_ptr) {} static int ImageLoaderHelperFormatToColorChannel(EImageFormat Format) { - if(Format == IMAGE_FORMAT_R) + switch(Format) + { + case IMAGE_FORMAT_R: return 1; - else if(Format == IMAGE_FORMAT_RGB) + case IMAGE_FORMAT_RA: + return 2; + case IMAGE_FORMAT_RGB: return 3; - else if(Format == IMAGE_FORMAT_RGBA) + case IMAGE_FORMAT_RGBA: return 4; - - return 4; + default: + dbg_assert(false, "Format invalid"); + dbg_break(); + } } bool SavePNG(EImageFormat ImageFormat, const uint8_t *pRawBuffer, SImageByteBuffer &WrittenBytes, int Width, int Height) diff --git a/src/engine/gfx/image_loader.h b/src/engine/gfx/image_loader.h index 72a176e4e04..0da2474a0f4 100644 --- a/src/engine/gfx/image_loader.h +++ b/src/engine/gfx/image_loader.h @@ -8,6 +8,7 @@ enum EImageFormat { IMAGE_FORMAT_R = 0, + IMAGE_FORMAT_RA, IMAGE_FORMAT_RGB, IMAGE_FORMAT_RGBA, }; diff --git a/src/engine/graphics.h b/src/engine/graphics.h index dac4a31076f..67043c5b30f 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -320,7 +320,7 @@ class IGraphics : public IInterface virtual const TTWGraphicsGPUList &GetGPUs() const = 0; - virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) = 0; + virtual bool LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) = 0; virtual void FreePNG(CImageInfo *pImg) = 0; virtual bool CheckImageDivisibility(const char *pFileName, CImageInfo &Img, int DivX, int DivY, bool AllowResize) = 0; diff --git a/src/engine/server.h b/src/engine/server.h index e3ae46f3094..55c5cc7a48f 100644 --- a/src/engine/server.h +++ b/src/engine/server.h @@ -29,7 +29,6 @@ class IServer : public IInterface MACRO_INTERFACE("server", 0) protected: int m_CurrentGameTick; - int m_TickSpeed; public: /* @@ -46,7 +45,7 @@ class IServer : public IInterface }; int Tick() const { return m_CurrentGameTick; } - int TickSpeed() const { return m_TickSpeed; } + int TickSpeed() const { return SERVER_TICK_SPEED; } virtual int Port() const = 0; virtual int MaxClients() const = 0; @@ -205,8 +204,8 @@ class IServer : public IInterface virtual void GetMapInfo(char *pMapName, int MapNameSize, int *pMapSize, SHA256_DIGEST *pSha256, int *pMapCrc) = 0; virtual bool WouldClientNameChange(int ClientID, const char *pNameRequest) = 0; - virtual void SetClientName(int ClientID, char const *pName) = 0; - virtual void SetClientClan(int ClientID, char const *pClan) = 0; + virtual void SetClientName(int ClientID, const char *pName) = 0; + virtual void SetClientClan(int ClientID, const char *pClan) = 0; virtual void SetClientCountry(int ClientID, int Country) = 0; virtual void SetClientScore(int ClientID, std::optional Score) = 0; virtual void SetClientFlags(int ClientID, int Flags) = 0; @@ -253,7 +252,7 @@ class IServer : public IInterface virtual bool DnsblWhite(int ClientID) = 0; virtual bool DnsblPending(int ClientID) = 0; virtual bool DnsblBlack(int ClientID) = 0; - virtual const char *GetAnnouncementLine(char const *pFileName) = 0; + virtual const char *GetAnnouncementLine(const char *pFileName) = 0; virtual bool ClientPrevIngame(int ClientID) = 0; virtual const char *GetNetErrorString(int ClientID) = 0; virtual void ResetNetErrorString(int ClientID) = 0; diff --git a/src/engine/server/antibot.cpp b/src/engine/server/antibot.cpp index 1ec699b2e81..238e8420f5b 100644 --- a/src/engine/server/antibot.cpp +++ b/src/engine/server/antibot.cpp @@ -23,6 +23,11 @@ CAntibot::~CAntibot() if(m_Initialized) AntibotDestroy(); } +void CAntibot::Kick(int ClientID, const char *pMessage, void *pUser) +{ + CAntibot *pAntibot = (CAntibot *)pUser; + pAntibot->Server()->Kick(ClientID, pMessage); +} void CAntibot::Log(const char *pMessage, void *pUser) { CAntibot *pAntibot = (CAntibot *)pUser; @@ -67,6 +72,7 @@ void CAntibot::Init() m_Data.m_Now = time_get(); m_Data.m_Freq = time_freq(); + m_Data.m_pfnKick = Kick; m_Data.m_pfnLog = Log; m_Data.m_pfnReport = Report; m_Data.m_pfnSend = Send; @@ -92,7 +98,10 @@ void CAntibot::RoundEnd() m_pGameServer = 0; free(m_RoundData.m_Map.m_pTiles); } -void CAntibot::Dump() { AntibotDump(); } +void CAntibot::ConsoleCommand(const char *pCommand) +{ + AntibotConsoleCommand(pCommand); +} void CAntibot::Update() { m_Data.m_Now = time_get(); @@ -221,9 +230,16 @@ void CAntibot::RoundEnd() { m_pGameServer = 0; } -void CAntibot::Dump() +void CAntibot::ConsoleCommand(const char *pCommand) { - Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "antibot", "antibot support not compiled in"); + if(str_comp(pCommand, "dump") == 0) + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "antibot", "antibot support not compiled in"); + } + else + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "antibot", "unknown command"); + } } void CAntibot::Update() { diff --git a/src/engine/server/antibot.h b/src/engine/server/antibot.h index 0569c2d8da8..00af4b0aee1 100644 --- a/src/engine/server/antibot.h +++ b/src/engine/server/antibot.h @@ -19,6 +19,7 @@ class CAntibot : public IEngineAntibot bool m_Initialized; void Update(); + static void Kick(int ClientID, const char *pMessage, void *pUser); static void Log(const char *pMessage, void *pUser); static void Report(int ClientID, const char *pMessage, void *pUser); static void Send(int ClientID, const void *pData, int Size, int Flags, void *pUser); @@ -52,7 +53,7 @@ class CAntibot : public IEngineAntibot void OnCharacterTick(int ClientID) override; void OnHookAttach(int ClientID, bool Player) override; - void Dump() override; + void ConsoleCommand(const char *pCommand) override; }; extern IEngineAntibot *CreateEngineAntibot(); diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index d6008d6d072..3b2f9674323 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -317,8 +317,6 @@ CServer::CServer() m_aDemoRecorder[i] = CDemoRecorder(&m_SnapshotDelta, true); m_aDemoRecorder[MAX_CLIENTS] = CDemoRecorder(&m_SnapshotDelta, false); - m_TickSpeed = SERVER_TICK_SPEED; - m_pGameServer = 0; m_CurrentGameTick = MIN_TICK; @@ -558,7 +556,7 @@ void CServer::RedirectClient(int ClientID, int Port, bool Verbose) int64_t CServer::TickStartTime(int Tick) { - return m_GameStartTime + (time_freq() * Tick) / SERVER_TICK_SPEED; + return m_GameStartTime + (time_freq() * Tick) / TickSpeed(); } int CServer::Init() @@ -573,6 +571,7 @@ int CServer::Init() Client.m_Traffic = 0; Client.m_TrafficSince = 0; Client.m_ShowIps = false; + Client.m_DebugDummy = false; Client.m_AuthKey = -1; Client.m_Latency = 0; Client.m_Sixup = false; @@ -942,7 +941,7 @@ void CServer::DoSnapshot() continue; // this client is trying to recover, don't spam snapshots - if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_RECOVER && (Tick() % 50) != 0) + if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_RECOVER && (Tick() % TickSpeed()) != 0) continue; // this client is trying to recover, don't spam snapshots @@ -969,7 +968,7 @@ void CServer::DoSnapshot() // remove old snapshots // keep 3 seconds worth of snapshots - m_aClients[i].m_Snapshots.PurgeUntil(m_CurrentGameTick - SERVER_TICK_SPEED * 3); + m_aClients[i].m_Snapshots.PurgeUntil(m_CurrentGameTick - TickSpeed() * 3); // save the snapshot m_aClients[i].m_Snapshots.Add(m_CurrentGameTick, time_get(), SnapshotSize, pData, 0, nullptr); @@ -1083,6 +1082,7 @@ int CServer::NewClientNoAuthCallback(int ClientID, void *pUser) pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_aClients[ClientID].m_pRconCmdToSend = 0; pThis->m_aClients[ClientID].m_ShowIps = false; + pThis->m_aClients[ClientID].m_DebugDummy = false; pThis->m_aClients[ClientID].m_DDNetVersion = VERSION_NONE; pThis->m_aClients[ClientID].m_GotDDNetVersionPacket = false; pThis->m_aClients[ClientID].m_DDNetVersionSettled = false; @@ -1114,6 +1114,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser, bool Sixup) pThis->m_aClients[ClientID].m_Traffic = 0; pThis->m_aClients[ClientID].m_TrafficSince = 0; pThis->m_aClients[ClientID].m_ShowIps = false; + pThis->m_aClients[ClientID].m_DebugDummy = false; pThis->m_aClients[ClientID].m_DDNetVersion = VERSION_NONE; pThis->m_aClients[ClientID].m_GotDDNetVersionPacket = false; pThis->m_aClients[ClientID].m_DDNetVersionSettled = false; @@ -1200,6 +1201,7 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) pThis->m_aClients[ClientID].m_Traffic = 0; pThis->m_aClients[ClientID].m_TrafficSince = 0; pThis->m_aClients[ClientID].m_ShowIps = false; + pThis->m_aClients[ClientID].m_DebugDummy = false; pThis->m_aPrevStates[ClientID] = CClient::STATE_EMPTY; pThis->m_aClients[ClientID].m_Snapshots.PurgeAll(); pThis->m_aClients[ClientID].m_Sixup = false; @@ -1933,7 +1935,7 @@ void CServer::CacheServerInfo(CCache *pCache, int Type, bool SendClients) int PlayerCount = 0, ClientCount = 0; for(int i = 0; i < MAX_CLIENTS; i++) { - if(m_aClients[i].m_State != CClient::STATE_EMPTY) + if(m_aClients[i].IncludedInServerInfo()) { if(GameServer()->IsClientPlayer(i)) PlayerCount++; @@ -2065,7 +2067,7 @@ void CServer::CacheServerInfo(CCache *pCache, int Type, bool SendClients) for(int i = 0; i < MAX_CLIENTS; i++) { - if(m_aClients[i].m_State != CClient::STATE_EMPTY) + if(m_aClients[i].IncludedInServerInfo()) { if(Remaining == 0) { @@ -2147,7 +2149,7 @@ void CServer::CacheServerInfoSixup(CCache *pCache, bool SendClients) int PlayerCount = 0, ClientCount = 0; for(int i = 0; i < MAX_CLIENTS; i++) { - if(m_aClients[i].m_State != CClient::STATE_EMPTY) + if(m_aClients[i].IncludedInServerInfo()) { if(GameServer()->IsClientPlayer(i)) PlayerCount++; @@ -2183,7 +2185,7 @@ void CServer::CacheServerInfoSixup(CCache *pCache, bool SendClients) { for(int i = 0; i < MAX_CLIENTS; i++) { - if(m_aClients[i].m_State != CClient::STATE_EMPTY) + if(m_aClients[i].IncludedInServerInfo()) { Packer.AddString(ClientName(i), MAX_NAME_LENGTH); // client name Packer.AddString(ClientClan(i), MAX_CLAN_LENGTH); // client clan @@ -2286,7 +2288,7 @@ void CServer::UpdateRegisterServerInfo() int PlayerCount = 0, ClientCount = 0; for(int i = 0; i < MAX_CLIENTS; i++) { - if(m_aClients[i].m_State != CClient::STATE_EMPTY) + if(m_aClients[i].IncludedInServerInfo()) { if(GameServer()->IsClientPlayer(i)) PlayerCount++; @@ -2334,7 +2336,7 @@ void CServer::UpdateRegisterServerInfo() bool FirstPlayer = true; for(int i = 0; i < MAX_CLIENTS; i++) { - if(m_aClients[i].m_State != CClient::STATE_EMPTY) + if(m_aClients[i].IncludedInServerInfo()) { char aCName[32]; char aCClan[32]; @@ -2615,6 +2617,45 @@ int CServer::LoadMap(const char *pMapName) return 1; } +#ifdef CONF_DEBUG +void CServer::UpdateDebugDummies(bool ForceDisconnect) +{ + if(m_PreviousDebugDummies == g_Config.m_DbgDummies && !ForceDisconnect) + return; + + for(int DummyIndex = 0; DummyIndex < maximum(m_PreviousDebugDummies, g_Config.m_DbgDummies); ++DummyIndex) + { + const bool AddDummy = !ForceDisconnect && DummyIndex < g_Config.m_DbgDummies; + const int ClientID = MAX_CLIENTS - DummyIndex - 1; + if(AddDummy && m_aClients[ClientID].m_State == CClient::STATE_EMPTY) + { + NewClientCallback(ClientID, this, false); + m_aClients[ClientID].m_DebugDummy = true; + GameServer()->OnClientConnected(ClientID, nullptr); + m_aClients[ClientID].m_State = CClient::STATE_INGAME; + str_format(m_aClients[ClientID].m_aName, sizeof(m_aClients[ClientID].m_aName), "Debug dummy %d", DummyIndex + 1); + GameServer()->OnClientEnter(ClientID); + } + else if(!AddDummy && m_aClients[ClientID].m_DebugDummy) + { + DelClientCallback(ClientID, "Dropping debug dummy", this); + } + + if(AddDummy && m_aClients[ClientID].m_DebugDummy) + { + CNetObj_PlayerInput Input = {0}; + Input.m_Direction = (ClientID & 1) ? -1 : 1; + m_aClients[ClientID].m_aInputs[0].m_GameTick = Tick() + 1; + mem_copy(m_aClients[ClientID].m_aInputs[0].m_aData, &Input, minimum(sizeof(Input), sizeof(m_aClients[ClientID].m_aInputs[0].m_aData))); + m_aClients[ClientID].m_LatestInput = m_aClients[ClientID].m_aInputs[0]; + m_aClients[ClientID].m_CurrentInput = 0; + } + } + + m_PreviousDebugDummies = ForceDisconnect ? 0 : g_Config.m_DbgDummies; +} +#endif + int CServer::Run() { if(m_RunServer == UNINITIALIZED) @@ -2762,6 +2803,9 @@ int CServer::Run() } } +#ifdef CONF_DEBUG + UpdateDebugDummies(true); +#endif GameServer()->OnShutdown(m_pPersistentData); for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++) @@ -2851,6 +2895,10 @@ int CServer::Run() { GameServer()->OnPreTickTeehistorian(); +#ifdef CONF_DEBUG + UpdateDebugDummies(false); +#endif + for(int c = 0; c < MAX_CLIENTS; c++) { if(m_aClients[c].m_State != CClient::STATE_INGAME) @@ -3868,7 +3916,7 @@ void CServer::GetClientAddr(int ClientID, NETADDR *pAddr) const } } -const char *CServer::GetAnnouncementLine(char const *pFileName) +const char *CServer::GetAnnouncementLine(const char *pFileName) { if(str_comp(pFileName, m_aAnnouncementFile) != 0) { diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 3d0e3e873e3..3dd469b4956 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -122,6 +122,11 @@ class CServer : public IServer class CDbConnectionPool *m_pConnectionPool; +#ifdef CONF_DEBUG + int m_PreviousDebugDummies = 0; + void UpdateDebugDummies(bool ForceDisconnect); +#endif + public: class IGameServer *GameServer() { return m_pGameServer; } class CConfig *Config() { return m_pConfig; } @@ -192,6 +197,7 @@ class CServer : public IServer int m_NextMapChunk; int m_Flags; bool m_ShowIps; + bool m_DebugDummy; const IConsole::CCommandInfo *m_pRconCmdToSend; @@ -215,6 +221,11 @@ class CServer : public IServer std::shared_ptr m_pDnsblLookup; bool m_Sixup; + + bool IncludedInServerInfo() const + { + return m_State != STATE_EMPTY && !m_DebugDummy; + } }; CClient m_aClients[MAX_CLIENTS]; @@ -288,7 +299,7 @@ class CServer : public IServer bool WouldClientNameChange(int ClientID, const char *pNameRequest) override; void SetClientName(int ClientID, const char *pName) override; - void SetClientClan(int ClientID, char const *pClan) override; + void SetClientClan(int ClientID, const char *pClan) override; void SetClientCountry(int ClientID, int Country) override; void SetClientScore(int ClientID, std::optional Score) override; void SetClientFlags(int ClientID, int Flags) override; @@ -457,7 +468,7 @@ class CServer : public IServer void GetClientAddr(int ClientID, NETADDR *pAddr) const override; int m_aPrevStates[MAX_CLIENTS]; - const char *GetAnnouncementLine(char const *pFileName) override; + const char *GetAnnouncementLine(const char *pFileName) override; int *GetIdMap(int ClientID) override; diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h index 5c124f48f2a..a365c9e44fb 100644 --- a/src/engine/serverbrowser.h +++ b/src/engine/serverbrowser.h @@ -209,31 +209,29 @@ class CCommunity char m_aId[CServerInfo::MAX_COMMUNITY_ID_LENGTH]; char m_aName[64]; - char m_aJsonServersKey[32]; - char m_aJsonRanksKey[32]; SHA256_DIGEST m_IconSha256; + char m_aIconUrl[128]; std::vector m_vCountries; std::vector m_vTypes; - std::unordered_set m_RankedMaps; + bool m_HasFinishes = false; + std::unordered_set m_FinishedMaps; public: - CCommunity(const char *pId, const char *pName, const char *pJsonServersKey, const char *pJsonRanksKey, SHA256_DIGEST IconSha256) : + CCommunity(const char *pId, const char *pName, SHA256_DIGEST IconSha256, const char *pIconUrl) : m_IconSha256(IconSha256) { str_copy(m_aId, pId); str_copy(m_aName, pName); - str_copy(m_aJsonServersKey, pJsonServersKey); - str_copy(m_aJsonRanksKey, pJsonRanksKey); + str_copy(m_aIconUrl, pIconUrl); } const char *Id() const { return m_aId; } const char *Name() const { return m_aName; } - const char *JsonServersKey() const { return m_aJsonServersKey; } - const char *JsonRanksKey() const { return m_aJsonRanksKey; } + const char *IconUrl() const { return m_aIconUrl; } const SHA256_DIGEST &IconSha256() const { return m_IconSha256; } const std::vector &Countries() const { return m_vCountries; } const std::vector &Types() const { return m_vTypes; } - bool HasRanks() const { return m_aJsonRanksKey[0] != '\0'; } + bool HasRanks() const { return m_HasFinishes; } CServerInfo::ERankState HasRank(const char *pMap) const; }; diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 9e2b9629ebf..39b2bae3548 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -1289,7 +1289,18 @@ void CConsole::ResetGameSettings() } \ } -#define MACRO_CONFIG_COL(Name, ScriptName, Def, Save, Desc) MACRO_CONFIG_INT(Name, ScriptName, Def, 0, 0, Save, Desc) +#define MACRO_CONFIG_COL(Name, ScriptName, Def, Flags, Desc) \ + { \ + if(((Flags)&CFGFLAG_GAME) == CFGFLAG_GAME) \ + { \ + CCommand *pCommand = FindCommand(#ScriptName, CFGFLAG_GAME); \ + void *pUserData = pCommand->m_pUserData; \ + FCommandCallback pfnCallback = pCommand->m_pfnCallback; \ + TraverseChain(&pfnCallback, &pUserData); \ + CColVariableData *pData = (CColVariableData *)pUserData; \ + *pData->m_pVariable = pData->m_OldValue; \ + } \ + } #define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Flags, Desc) \ { \ @@ -1300,7 +1311,7 @@ void CConsole::ResetGameSettings() FCommandCallback pfnCallback = pCommand->m_pfnCallback; \ TraverseChain(&pfnCallback, &pUserData); \ CStrVariableData *pData = (CStrVariableData *)pUserData; \ - str_copy(pData->m_pOldValue, pData->m_pStr, pData->m_MaxSize); \ + str_copy(pData->m_pStr, pData->m_pOldValue, pData->m_MaxSize); \ } \ } diff --git a/src/engine/shared/netban.h b/src/engine/shared/netban.h index f21060f6f67..fd7dbb8a857 100644 --- a/src/engine/shared/netban.h +++ b/src/engine/shared/netban.h @@ -66,7 +66,7 @@ class CNetBan int m_Hash; int m_HashIndex; // matching parts for ranges, 0 for addr - CNetHash() {} + CNetHash() = default; CNetHash(const NETADDR *pAddr); CNetHash(const CNetRange *pRange); diff --git a/src/engine/shared/network_client.cpp b/src/engine/shared/network_client.cpp index 7b52665cbe9..a9781547524 100644 --- a/src/engine/shared/network_client.cpp +++ b/src/engine/shared/network_client.cpp @@ -12,7 +12,7 @@ bool CNetClient::Open(NETADDR BindAddr) return false; // clean it - mem_zero(this, sizeof(*this)); + *this = CNetClient{}; // init m_Socket = Socket; diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index 38874bc153c..27c2fd2d16f 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -8,7 +8,7 @@ bool CNetConsole::Open(NETADDR BindAddr, CNetBan *pNetBan) { // zero out the whole structure - mem_zero(this, sizeof(*this)); + *this = CNetConsole{}; m_pNetBan = pNetBan; // open socket diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index 14c4029844d..0dd81393c7f 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -44,7 +44,8 @@ static SECURITY_TOKEN ToSecurityToken(const unsigned char *pData) bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP) { // zero out the whole structure - mem_zero(this, sizeof(*this)); + this->~CNetServer(); + new(this) CNetServer{}; // open socket m_Socket = net_udp_create(BindAddr); diff --git a/src/engine/shared/packer.cpp b/src/engine/shared/packer.cpp index 2e64bbc3cbd..2b183113b16 100644 --- a/src/engine/shared/packer.cpp +++ b/src/engine/shared/packer.cpp @@ -72,12 +72,8 @@ void CPacker::AddRaw(const void *pData, int Size) return; } - const unsigned char *pSrc = (const unsigned char *)pData; - while(Size) - { - *m_pCurrent++ = *pSrc++; - Size--; - } + mem_copy(m_pCurrent, pData, Size); + m_pCurrent += Size; } void CUnpacker::Reset(const void *pData, int Size) @@ -134,7 +130,8 @@ int CUnpacker::GetUncompressedInt() return 0; } - int i = *(int *)m_pCurrent; + int i; + mem_copy(&i, m_pCurrent, sizeof(int)); m_pCurrent += sizeof(int); return i; } diff --git a/src/engine/shared/ringbuffer.cpp b/src/engine/shared/ringbuffer.cpp index 20ec3af7537..23301a669bb 100644 --- a/src/engine/shared/ringbuffer.cpp +++ b/src/engine/shared/ringbuffer.cpp @@ -46,9 +46,10 @@ CRingBufferBase::CItem *CRingBufferBase::MergeBack(CItem *pItem) void CRingBufferBase::Init(void *pMemory, int Size, int Flags) { - mem_zero(pMemory, Size); m_Size = (Size) / sizeof(CItem) * sizeof(CItem); m_pFirst = (CItem *)pMemory; + m_pFirst->m_pPrev = nullptr; + m_pFirst->m_pNext = nullptr; m_pFirst->m_Free = 1; m_pFirst->m_Size = m_Size; m_pLast = m_pFirst; diff --git a/src/game/client/components/camera.cpp b/src/game/client/components/camera.cpp index 9dc393a9063..4837be0ba3e 100644 --- a/src/game/client/components/camera.cpp +++ b/src/game/client/components/camera.cpp @@ -24,6 +24,10 @@ CCamera::CCamera() m_GotoTeleOffset = 0; m_GotoSwitchLastPos = ivec2(-1, -1); m_GotoTeleLastPos = ivec2(-1, -1); + + mem_zero(m_aLastPos, sizeof(m_aLastPos)); + m_PrevCenter = vec2(0, 0); + m_Center = vec2(0, 0); } float CCamera::ZoomProgress(float CurrentTime) const diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp index 09c6a0a56cc..c52d077f314 100644 --- a/src/game/client/components/chat.cpp +++ b/src/game/client/components/chat.cpp @@ -398,6 +398,19 @@ bool CChat::OnInput(const IInput::CEvent &Event) // add part before the name str_truncate(aBuf, sizeof(aBuf), m_Input.GetString(), m_PlaceholderOffset); + // quote the name + char aQuoted[128]; + if(m_Input.GetString()[0] == '/' && (str_find(pCompletionString, " ") || str_find(pCompletionString, "\""))) + { + // escape the name + str_copy(aQuoted, "\""); + char *pDst = aQuoted + str_length(aQuoted); + str_escape(&pDst, pCompletionString, aQuoted + sizeof(aQuoted)); + str_append(aQuoted, "\""); + + pCompletionString = aQuoted; + } + // add the name str_append(aBuf, pCompletionString); diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index a7024d17dac..3e067ed3072 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -134,22 +134,41 @@ void CGameConsole::CInstance::Init(CGameConsole *pGameConsole) void CGameConsole::CInstance::ClearBacklog() { - const CLockScope LockScope(m_BacklogLock); + { + // We must ensure that no log messages are printed while owning + // m_BacklogPendingLock or this will result in a dead lock. + const CLockScope LockScope(m_BacklogPendingLock); + m_BacklogPending.Init(); + } + m_Backlog.Init(); m_BacklogCurPage = 0; } void CGameConsole::CInstance::ClearBacklogYOffsets() { - const CLockScope LockScope(m_BacklogLock); - auto *pEntry = m_Backlog.First(); - while(pEntry) + // Pending backlog entries are not handled because they don't have a Y offset yet. + for(CInstance::CBacklogEntry *pEntry = m_Backlog.First(); pEntry; pEntry = m_Backlog.Next(pEntry)) { pEntry->m_YOffset = -1.0f; - pEntry = m_Backlog.Next(pEntry); } } +void CGameConsole::CInstance::PumpBacklogPending() +{ + // We must ensure that no log messages are printed while owning + // m_BacklogPendingLock or this will result in a dead lock. + const CLockScope LockScopePending(m_BacklogPendingLock); + for(CInstance::CBacklogEntry *pPendingEntry = m_BacklogPending.First(); pPendingEntry; pPendingEntry = m_BacklogPending.Next(pPendingEntry)) + { + const size_t EntrySize = sizeof(CBacklogEntry) + pPendingEntry->m_Length; + CBacklogEntry *pEntry = m_Backlog.Allocate(EntrySize); + mem_copy(pEntry, pPendingEntry, EntrySize); + ++m_NewLineCounter; + } + m_BacklogPending.Init(); +} + void CGameConsole::CInstance::ClearHistory() { m_History.Init(); @@ -235,6 +254,10 @@ bool CGameConsole::CInstance::OnInput(const IInput::CEvent &Event) { char *pEntry = m_History.Allocate(m_Input.GetLength() + 1); str_copy(pEntry, m_Input.GetString(), m_Input.GetLength() + 1); + // print out the user's commands before they get run + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "> %s", m_Input.GetString()); + m_pGameConsole->PrintLine(m_Type, aBuf); } } ExecuteLine(m_Input.GetString()); @@ -398,12 +421,14 @@ bool CGameConsole::CInstance::OnInput(const IInput::CEvent &Event) void CGameConsole::CInstance::PrintLine(const char *pLine, int Len, ColorRGBA PrintColor) { - const CLockScope LockScope(m_BacklogLock); - CBacklogEntry *pEntry = m_Backlog.Allocate(sizeof(CBacklogEntry) + Len); + // We must ensure that no log messages are printed while owning + // m_BacklogPendingLock or this will result in a dead lock. + const CLockScope LockScope(m_BacklogPendingLock); + CBacklogEntry *pEntry = m_BacklogPending.Allocate(sizeof(CBacklogEntry) + Len); pEntry->m_YOffset = -1.0f; pEntry->m_PrintColor = PrintColor; + pEntry->m_Length = Len; str_copy(pEntry->m_aText, pLine, Len + 1); - m_NewLineCounter++; } CGameConsole::CGameConsole() : @@ -737,7 +762,7 @@ void CGameConsole::OnRender() UI()->DoSmoothScrollLogic(&pConsole->m_CompletionRenderOffset, &pConsole->m_CompletionRenderOffsetChange, Info.m_Width, Info.m_TotalWidth); } - pConsole->m_BacklogLock.lock(); + pConsole->PumpBacklogPending(); // render log (current page, wrap lines) CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.Last(); @@ -820,8 +845,6 @@ void CGameConsole::OnRender() pConsole->m_BacklogCurPage = clamp(pConsole->m_BacklogCurPage, 0, TotalPages - 1); pConsole->m_BacklogLastActivePage = pConsole->m_BacklogCurPage; - pConsole->m_BacklogLock.unlock(); - if(m_WantsSelectionCopy && !SelectionString.empty()) { pConsole->m_HasSelection = false; @@ -913,10 +936,10 @@ void CGameConsole::Dump(int Type) IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(File) { - const CLockScope LockScope(pConsole->m_BacklogLock); + pConsole->PumpBacklogPending(); for(CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.First(); pEntry; pEntry = pConsole->m_Backlog.Next(pEntry)) { - io_write(File, pEntry->m_aText, str_length(pEntry->m_aText)); + io_write(File, pEntry->m_aText, pEntry->m_Length); io_write_newline(File); } io_close(File); diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h index 087f1097cbd..b088f064295 100644 --- a/src/game/client/components/console.h +++ b/src/game/client/components/console.h @@ -31,10 +31,12 @@ class CGameConsole : public CComponent { float m_YOffset; ColorRGBA m_PrintColor; + size_t m_Length; char m_aText[1]; }; - CLock m_BacklogLock; CStaticRingBuffer m_Backlog; + CLock m_BacklogPendingLock; + CStaticRingBuffer m_BacklogPending GUARDED_BY(m_BacklogPendingLock); CStaticRingBuffer m_History; char *m_pHistoryEntry; @@ -77,15 +79,16 @@ class CGameConsole : public CComponent CInstance(int t); void Init(CGameConsole *pGameConsole); - void ClearBacklog() REQUIRES(!m_BacklogLock); - void ClearBacklogYOffsets() REQUIRES(!m_BacklogLock); + void ClearBacklog() REQUIRES(!m_BacklogPendingLock); + void ClearBacklogYOffsets(); + void PumpBacklogPending() REQUIRES(!m_BacklogPendingLock); void ClearHistory(); void Reset(); void ExecuteLine(const char *pLine); bool OnInput(const IInput::CEvent &Event); - void PrintLine(const char *pLine, int Len, ColorRGBA PrintColor) REQUIRES(!m_BacklogLock); + void PrintLine(const char *pLine, int Len, ColorRGBA PrintColor) REQUIRES(!m_BacklogPendingLock); const char *GetString() const { return m_Input.GetString(); } static void PossibleCommandsCompleteCallback(int Index, const char *pStr, void *pUser); diff --git a/src/game/client/components/controls.cpp b/src/game/client/components/controls.cpp index c1c0ed9ed36..fc4c590bc83 100644 --- a/src/game/client/components/controls.cpp +++ b/src/game/client/components/controls.cpp @@ -20,6 +20,10 @@ CControls::CControls() mem_zero(&m_aLastData, sizeof(m_aLastData)); m_LastDummy = 0; m_OtherFire = 0; + + mem_zero(m_aMousePos, sizeof(m_aMousePos)); + mem_zero(m_aMousePosOnAction, sizeof(m_aMousePosOnAction)); + mem_zero(m_aTargetPos, sizeof(m_aTargetPos)); } void CControls::OnReset() diff --git a/src/game/client/components/damageind.cpp b/src/game/client/components/damageind.cpp index b9c6e06f3dd..031fc9aa9c3 100644 --- a/src/game/client/components/damageind.cpp +++ b/src/game/client/components/damageind.cpp @@ -40,7 +40,7 @@ void CDamageInd::Create(vec2 Pos, vec2 Dir, float Alpha) { pItem->m_Pos = Pos; pItem->m_StartTime = LocalTime(); - pItem->m_Dir = Dir * -1; + pItem->m_Dir = -Dir; pItem->m_StartAngle = -random_angle(); pItem->m_Color = ColorRGBA(1.0f, 1.0f, 1.0f, Alpha); pItem->m_StartAlpha = Alpha; diff --git a/src/game/client/components/ghost.cpp b/src/game/client/components/ghost.cpp index f8b71ee802c..d15fa52a22b 100644 --- a/src/game/client/components/ghost.cpp +++ b/src/game/client/components/ghost.cpp @@ -628,6 +628,20 @@ void CGhost::OnMessage(int MsgType, void *pRawMsg) m_LastDeathTick = Client()->GameTick(g_Config.m_ClDummy); } } + else if(MsgType == NETMSGTYPE_SV_KILLMSGTEAM) + { + CNetMsg_Sv_KillMsgTeam *pMsg = (CNetMsg_Sv_KillMsgTeam *)pRawMsg; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(m_pClient->m_Teams.Team(i) == pMsg->m_Team && i == m_pClient->m_Snap.m_LocalClientID) + { + if(m_Recording) + StopRecord(); + StopRender(); + m_LastDeathTick = Client()->GameTick(g_Config.m_ClDummy); + } + } + } else if(MsgType == NETMSGTYPE_SV_CHAT) { CNetMsg_Sv_Chat *pMsg = (CNetMsg_Sv_Chat *)pRawMsg; diff --git a/src/game/client/components/items.cpp b/src/game/client/components/items.cpp index a5a1f8ffd01..8ffbffb6cd8 100644 --- a/src/game/client/components/items.cpp +++ b/src/game/client/components/items.cpp @@ -60,16 +60,16 @@ void CItems::RenderProjectile(const CProjectileData *pCurrent, int ItemID) float Ct; if(m_pClient->Predict() && m_pClient->AntiPingGrenade() && LocalPlayerInGame && !IsOtherTeam) - Ct = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)SERVER_TICK_SPEED; + Ct = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); else - Ct = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED + s_LastGameTickTime; + Ct = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)Client()->GameTickSpeed() + s_LastGameTickTime; if(Ct < 0) { if(Ct > -s_LastGameTickTime / 2) { // Fixup the timing which might be screwed during demo playback because // s_LastGameTickTime depends on the system timer, while the other part - // (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED + // (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)Client()->GameTickSpeed() // is virtually constant (for projectiles fired on the current game tick): // (x - (x+2)) / 50 = -0.04 // @@ -309,7 +309,7 @@ void CItems::RenderLaser(const CLaserData *pCurrent, bool IsPredicted) Ticks = (float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy); else Ticks = (float)(Client()->GameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->IntraGameTick(g_Config.m_ClDummy); - float Ms = (Ticks / 50.0f) * 1000.0f; + float Ms = (Ticks / Client()->GameTickSpeed()) * 1000.0f; float a = Ms / m_pClient->GetTuning(TuneZone)->m_LaserBounceDelay; a = clamp(a, 0.0f, 1.0f); float Ia = 1 - a; @@ -627,11 +627,11 @@ void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyT Speed = pTuning->m_GunSpeed; } - float Pt = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)SERVER_TICK_SPEED; + float Pt = ((float)(Client()->PredGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed(); if(Pt < 0) return; // projectile haven't been shot yet - float Gt = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)SERVER_TICK_SPEED + Client()->GameTickTime(g_Config.m_ClDummy); + float Gt = (Client()->PrevGameTick(g_Config.m_ClDummy) - pCurrent->m_StartTick) / (float)Client()->GameTickSpeed() + Client()->GameTickTime(g_Config.m_ClDummy); float Alpha = 1.f; if(pCurrent->m_ExtraInfo && pCurrent->m_Owner >= 0 && m_pClient->IsOtherTeam(pCurrent->m_Owner)) @@ -641,7 +641,7 @@ void CItems::ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyT float T = Pt; if(DestroyTick >= 0) - T = minimum(Pt, ((float)(DestroyTick - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)SERVER_TICK_SPEED); + T = minimum(Pt, ((float)(DestroyTick - 1 - pCurrent->m_StartTick) + Client()->PredIntraGameTick(g_Config.m_ClDummy)) / (float)Client()->GameTickSpeed()); float MinTrailSpan = 0.4f * ((pCurrent->m_Type == WEAPON_GRENADE) ? 0.5f : 0.25f); float Step = maximum(Client()->FrameTimeAvg(), (pCurrent->m_Type == WEAPON_GRENADE) ? 0.02f : 0.01f); diff --git a/src/game/client/components/killmessages.cpp b/src/game/client/components/killmessages.cpp index 82ec93a5312..ac62949c938 100644 --- a/src/game/client/components/killmessages.cpp +++ b/src/game/client/components/killmessages.cpp @@ -287,7 +287,7 @@ void CKillMessages::OnRender() for(int i = 1; i <= MAX_KILLMSGS; i++) { int r = (m_KillmsgCurrent + i) % MAX_KILLMSGS; - if(Client()->GameTick(g_Config.m_ClDummy) > m_aKillmsgs[r].m_Tick + 50 * 10) + if(Client()->GameTick(g_Config.m_ClDummy) > m_aKillmsgs[r].m_Tick + Client()->GameTickSpeed() * 10) continue; float x = StartX; diff --git a/src/game/client/components/menu_background.cpp b/src/game/client/components/menu_background.cpp index b9b0c97c000..7a6ee7b7834 100644 --- a/src/game/client/components/menu_background.cpp +++ b/src/game/client/components/menu_background.cpp @@ -54,6 +54,10 @@ std::array GenerateMenuBackgroundPositions() CMenuBackground::CMenuBackground() : CBackground(CMapLayers::TYPE_FULL_DESIGN, false) { + m_RotationCenter = vec2(0.0f, 0.0f); + m_AnimationStartPos = vec2(0.0f, 0.0f); + m_Camera.m_Center = vec2(0.0f, 0.0f); + m_Camera.m_PrevCenter = vec2(0.0f, 0.0f); // unused in this class m_ChangedPosition = false; ResetPositions(); diff --git a/src/game/client/components/menu_background.h b/src/game/client/components/menu_background.h index 777f922903e..a33f4d36bb5 100644 --- a/src/game/client/components/menu_background.h +++ b/src/game/client/components/menu_background.h @@ -81,7 +81,6 @@ class CMenuBackground : public CBackground CBackgroundEngineMap *CreateBGMap() override; - vec2 m_MenuCenter; vec2 m_RotationCenter; std::array m_aPositions; int m_CurrentPosition; diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 6636e66f18f..171ef66d509 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -688,8 +688,6 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) // community filter if((g_Config.m_UiPage == PAGE_INTERNET || g_Config.m_UiPage == PAGE_FAVORITES) && !ServerBrowser()->Communities().empty()) { - ServerBrowser()->CleanFilters(); - CUIRect Row; View.HSplitTop(6.0f, nullptr, &View); View.HSplitTop(19.0f, &Row, &View); @@ -1742,8 +1740,13 @@ void CMenus::ConchainFavoritesUpdate(IConsole::IResult *pResult, void *pUserData void CMenus::ConchainCommunitiesUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) { pfnCallback(pResult, pCallbackUserData); + CMenus *pThis = static_cast(pUserData); if(pResult->NumArguments() >= 1 && (g_Config.m_UiPage == PAGE_INTERNET || g_Config.m_UiPage == PAGE_FAVORITES)) - ((CMenus *)pUserData)->UpdateCommunityCache(true); + { + pThis->ServerBrowser()->CleanFilters(); + pThis->UpdateCommunityCache(true); + pThis->Client()->ServerBrowserUpdate(); + } } void CMenus::UpdateCommunityCache(bool Force) @@ -1989,10 +1992,6 @@ void CMenus::UpdateCommunityIcons() } } - const char *pDownloadUrl = Client()->CommunityIconsDownloadUrl(); - if(pDownloadUrl[0] == '\0') - return; - // Find added and updated community icons for(const auto &Community : ServerBrowser()->Communities()) { @@ -2006,9 +2005,7 @@ void CMenus::UpdateCommunityIcons() }); if(pExistingDownload == m_CommunityIconDownloadJobs.end() && (ExistingIcon == m_vCommunityIcons.end() || ExistingIcon->m_Sha256 != Community.IconSha256())) { - char aUrl[256]; - str_format(aUrl, sizeof(aUrl), "%s/%s.png", pDownloadUrl, Community.Id()); - std::shared_ptr pJob = std::make_shared(this, Community.Id(), aUrl); + std::shared_ptr pJob = std::make_shared(this, Community.Id(), Community.IconUrl()); Engine()->AddJob(pJob); m_CommunityIconDownloadJobs.push_back(pJob); } diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 578280fa9bf..3e69044e9b4 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -155,7 +155,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) static int s_SkipDurationIndex = 1; static const int s_aSkipDurationsSeconds[] = {1, 5, 10, 30, 60, 5 * 60, 10 * 60}; - const int DemoLengthSeconds = TotalTicks / SERVER_TICK_SPEED; + const int DemoLengthSeconds = TotalTicks / Client()->GameTickSpeed(); int NumDurationLabels = 0; for(size_t i = 0; i < std::size(s_aSkipDurationsSeconds); ++i) { @@ -445,9 +445,9 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) // draw time char aCurrentTime[32]; - str_time((int64_t)CurrentTick / SERVER_TICK_SPEED * 100, TIME_HOURS, aCurrentTime, sizeof(aCurrentTime)); + str_time((int64_t)CurrentTick / Client()->GameTickSpeed() * 100, TIME_HOURS, aCurrentTime, sizeof(aCurrentTime)); char aTotalTime[32]; - str_time((int64_t)TotalTicks / SERVER_TICK_SPEED * 100, TIME_HOURS, aTotalTime, sizeof(aTotalTime)); + str_time((int64_t)TotalTicks / Client()->GameTickSpeed() * 100, TIME_HOURS, aTotalTime, sizeof(aTotalTime)); str_format(aBuffer, sizeof(aBuffer), "%s / %s", aCurrentTime, aTotalTime); UI()->DoLabel(&SeekBar, aBuffer, SeekBar.h * 0.70f, TEXTALIGN_MC); @@ -491,7 +491,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) { const int HoveredTick = (int)(clamp((UI()->MouseX() - SeekBar.x - Rounding) / (float)(SeekBar.w - 2 * Rounding), 0.0f, 1.0f) * TotalTicks); static char s_aHoveredTime[32]; - str_time((int64_t)HoveredTick / SERVER_TICK_SPEED * 100, TIME_HOURS, s_aHoveredTime, sizeof(s_aHoveredTime)); + str_time((int64_t)HoveredTick / Client()->GameTickSpeed() * 100, TIME_HOURS, s_aHoveredTime, sizeof(s_aHoveredTime)); GameClient()->m_Tooltips.DoToolTip(pId, &SeekBar, s_aHoveredTime); } } @@ -779,11 +779,11 @@ void CMenus::RenderDemoPlayerSliceSavePopup(CUIRect MainView) const int64_t RealSliceBegin = g_Config.m_ClDemoSliceBegin == -1 ? 0 : (g_Config.m_ClDemoSliceBegin - pInfo->m_FirstTick); const int64_t RealSliceEnd = (g_Config.m_ClDemoSliceEnd == -1 ? pInfo->m_LastTick : g_Config.m_ClDemoSliceEnd) - pInfo->m_FirstTick; char aSliceBegin[32]; - str_time(RealSliceBegin / SERVER_TICK_SPEED * 100, TIME_HOURS, aSliceBegin, sizeof(aSliceBegin)); + str_time(RealSliceBegin / Client()->GameTickSpeed() * 100, TIME_HOURS, aSliceBegin, sizeof(aSliceBegin)); char aSliceEnd[32]; - str_time(RealSliceEnd / SERVER_TICK_SPEED * 100, TIME_HOURS, aSliceEnd, sizeof(aSliceEnd)); + str_time(RealSliceEnd / Client()->GameTickSpeed() * 100, TIME_HOURS, aSliceEnd, sizeof(aSliceEnd)); char aSliceLength[32]; - str_time((RealSliceEnd - RealSliceBegin) / SERVER_TICK_SPEED * 100, TIME_HOURS, aSliceLength, sizeof(aSliceLength)); + str_time((RealSliceEnd - RealSliceBegin) / Client()->GameTickSpeed() * 100, TIME_HOURS, aSliceLength, sizeof(aSliceLength)); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "%s: %s – %s", Localize("Cut interval"), aSliceBegin, aSliceEnd); UI()->DoLabel(&SliceInterval, aBuf, 18.0f, TEXTALIGN_ML); diff --git a/src/game/client/components/particles.h b/src/game/client/components/particles.h index 7b60aeea24c..eb32993ceb9 100644 --- a/src/game/client/components/particles.h +++ b/src/game/client/components/particles.h @@ -10,6 +10,7 @@ struct CParticle { void SetDefault() { + m_Pos = vec2(0, 0); m_Vel = vec2(0, 0); m_LifeSpan = 0; m_StartSize = 32; diff --git a/src/game/client/components/players.cpp b/src/game/client/components/players.cpp index 6fa6511677c..87cd222a047 100644 --- a/src/game/client/components/players.cpp +++ b/src/game/client/components/players.cpp @@ -377,15 +377,15 @@ void CPlayers::RenderPlayer( } bool PredictLocalWeapons = false; - float AttackTime = (Client()->PrevGameTick(g_Config.m_ClDummy) - Player.m_AttackTick) / (float)SERVER_TICK_SPEED + Client()->GameTickTime(g_Config.m_ClDummy); - float LastAttackTime = (Client()->PrevGameTick(g_Config.m_ClDummy) - Player.m_AttackTick) / (float)SERVER_TICK_SPEED + s_LastGameTickTime; + float AttackTime = (Client()->PrevGameTick(g_Config.m_ClDummy) - Player.m_AttackTick) / (float)Client()->GameTickSpeed() + Client()->GameTickTime(g_Config.m_ClDummy); + float LastAttackTime = (Client()->PrevGameTick(g_Config.m_ClDummy) - Player.m_AttackTick) / (float)Client()->GameTickSpeed() + s_LastGameTickTime; if(ClientID >= 0 && m_pClient->m_aClients[ClientID].m_IsPredictedLocal && m_pClient->AntiPingGunfire()) { PredictLocalWeapons = true; - AttackTime = (Client()->PredIntraGameTick(g_Config.m_ClDummy) + (Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Player.m_AttackTick)) / (float)SERVER_TICK_SPEED; - LastAttackTime = (s_LastPredIntraTick + (Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Player.m_AttackTick)) / (float)SERVER_TICK_SPEED; + AttackTime = (Client()->PredIntraGameTick(g_Config.m_ClDummy) + (Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Player.m_AttackTick)) / (float)Client()->GameTickSpeed(); + LastAttackTime = (s_LastPredIntraTick + (Client()->PredGameTick(g_Config.m_ClDummy) - 1 - Player.m_AttackTick)) / (float)Client()->GameTickSpeed(); } - float AttackTicksPassed = AttackTime * (float)SERVER_TICK_SPEED; + float AttackTicksPassed = AttackTime * (float)Client()->GameTickSpeed(); float Angle; if(Local && (!m_pClient->m_Snap.m_SpecInfo.m_Active || m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW) && Client()->State() != IClient::STATE_DEMOPLAYBACK) diff --git a/src/game/client/components/race_demo.cpp b/src/game/client/components/race_demo.cpp index 43ce4c78656..4f57bc5b45a 100644 --- a/src/game/client/components/race_demo.cpp +++ b/src/game/client/components/race_demo.cpp @@ -135,6 +135,15 @@ void CRaceDemo::OnMessage(int MsgType, void *pRawMsg) if(pMsg->m_Victim == m_pClient->m_Snap.m_LocalClientID && Client()->RaceRecord_IsRecording()) StopRecord(m_Time); } + else if(MsgType == NETMSGTYPE_SV_KILLMSGTEAM) + { + CNetMsg_Sv_KillMsgTeam *pMsg = (CNetMsg_Sv_KillMsgTeam *)pRawMsg; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(m_pClient->m_Teams.Team(i) == pMsg->m_Team && i == m_pClient->m_Snap.m_LocalClientID && Client()->RaceRecord_IsRecording()) + StopRecord(m_Time); + } + } else if(MsgType == NETMSGTYPE_SV_CHAT) { CNetMsg_Sv_Chat *pMsg = (CNetMsg_Sv_Chat *)pRawMsg; diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp index cb528251a77..87a074767cd 100644 --- a/src/game/client/components/spectator.cpp +++ b/src/game/client/components/spectator.cpp @@ -162,6 +162,7 @@ void CSpectator::ConMultiView(IConsole::IResult *pResult, void *pUserData) CSpectator::CSpectator() { + m_SelectorMouse = vec2(0.0f, 0.0f); OnReset(); m_OldMouseX = m_OldMouseY = 0.0f; } diff --git a/src/game/client/components/statboard.cpp b/src/game/client/components/statboard.cpp index 30136742b4c..71b35a1b42a 100644 --- a/src/game/client/components/statboard.cpp +++ b/src/game/client/components/statboard.cpp @@ -73,6 +73,20 @@ void CStatboard::OnMessage(int MsgType, void *pRawMsg) else pStats[pMsg->m_Victim].m_Suicides++; } + else if(MsgType == NETMSGTYPE_SV_KILLMSGTEAM) + { + CNetMsg_Sv_KillMsgTeam *pMsg = (CNetMsg_Sv_KillMsgTeam *)pRawMsg; + CGameClient::CClientStats *pStats = m_pClient->m_aStats; + + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(m_pClient->m_Teams.Team(i) == pMsg->m_Team) + { + pStats[i].m_Deaths++; + pStats[i].m_Suicides++; + } + } + } else if(MsgType == NETMSGTYPE_SV_CHAT) { CNetMsg_Sv_Chat *pMsg = (CNetMsg_Sv_Chat *)pRawMsg; diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 53fd68bab3d..634adcd33cb 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -394,7 +394,6 @@ void CGameClient::OnInit() str_format(aBuf, sizeof(aBuf), "initialisation finished after %.2fms", ((End - Start) * 1000) / (float)time_freq()); Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "gameclient", aBuf); - m_GameWorld.m_GameTickSpeed = SERVER_TICK_SPEED; m_GameWorld.m_pCollision = Collision(); m_GameWorld.m_pTuningList = m_aTuningList; @@ -989,6 +988,30 @@ void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker, int Conn, bool Dumm } } } + else if(MsgId == NETMSGTYPE_SV_KILLMSGTEAM) + { + CNetMsg_Sv_KillMsgTeam *pMsg = (CNetMsg_Sv_KillMsgTeam *)pRawMsg; + + // reset prediction + std::vector> vStrongWeakSorted; + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(m_Teams.Team(i) == pMsg->m_Team) + { + if(CCharacter *pChar = m_GameWorld.GetCharacterByID(i)) + { + pChar->ResetPrediction(); + vStrongWeakSorted.emplace_back(i, pMsg->m_First == i ? MAX_CLIENTS : pChar ? pChar->GetStrongWeakID() : 0); + } + m_GameWorld.ReleaseHooked(i); + } + } + std::stable_sort(vStrongWeakSorted.begin(), vStrongWeakSorted.end(), [](auto &Left, auto &Right) { return Left.second > Right.second; }); + for(auto ID : vStrongWeakSorted) + { + m_CharOrder.GiveWeak(ID.first); + } + } } void CGameClient::OnStateChange(int NewState, int OldState) @@ -2639,7 +2662,7 @@ void CGameClient::UpdatePrediction() } // advance the gameworld to the current gametick - if(pLocalChar && absolute(m_GameWorld.GameTick() - Client()->GameTick(g_Config.m_ClDummy)) < SERVER_TICK_SPEED) + if(pLocalChar && absolute(m_GameWorld.GameTick() - Client()->GameTick(g_Config.m_ClDummy)) < Client()->GameTickSpeed()) { for(int Tick = m_GameWorld.GameTick() + 1; Tick <= Client()->GameTick(g_Config.m_ClDummy); Tick++) { @@ -2770,7 +2793,7 @@ void CGameClient::DetectStrongHook() int ToPlayer = m_Snap.m_aCharacters[FromPlayer].m_Prev.m_HookedPlayer; if(ToPlayer < 0 || ToPlayer >= MAX_CLIENTS || !m_Snap.m_aCharacters[ToPlayer].m_Active || ToPlayer != m_Snap.m_aCharacters[FromPlayer].m_Cur.m_HookedPlayer) continue; - if(absolute(minimum(m_aLastUpdateTick[ToPlayer], m_aLastUpdateTick[FromPlayer]) - Client()->GameTick(g_Config.m_ClDummy)) < SERVER_TICK_SPEED / 4) + if(absolute(minimum(m_aLastUpdateTick[ToPlayer], m_aLastUpdateTick[FromPlayer]) - Client()->GameTick(g_Config.m_ClDummy)) < Client()->GameTickSpeed() / 4) continue; if(m_Snap.m_aCharacters[FromPlayer].m_Prev.m_Direction != m_Snap.m_aCharacters[FromPlayer].m_Cur.m_Direction || m_Snap.m_aCharacters[ToPlayer].m_Prev.m_Direction != m_Snap.m_aCharacters[ToPlayer].m_Cur.m_Direction) continue; @@ -3867,6 +3890,8 @@ float CGameClient::CalculateMultiViewZoom(vec2 MinPos, vec2 MaxPos, float Vel) float Diff = clamp(MapValue(70.0f, 15.0f, Zoom * 0.10f, 0.0f, Vel), 0.0f, Zoom * 0.10f); // zoom should stay between 1.1 and 20.0 Zoom = clamp(Zoom + Diff, 1.1f, 20.0f); + // dont go below default zoom + Zoom = std::max(float(std::pow(CCamera::ZOOM_STEP, g_Config.m_ClDefaultZoom - 10)), Zoom); // add the user preference Zoom -= (Zoom * 0.1f) * m_MultiViewPersonalZoom; m_MultiView.m_OldPersonalZoom = m_MultiViewPersonalZoom; diff --git a/src/game/client/prediction/entities/character.cpp b/src/game/client/prediction/entities/character.cpp index 701e5b3875c..d73e9940355 100644 --- a/src/game/client/prediction/entities/character.cpp +++ b/src/game/client/prediction/entities/character.cpp @@ -457,7 +457,7 @@ void CCharacter::FireWeapon() break; } - m_AttackTick = GameWorld()->GameTick(); + m_AttackTick = GameWorld()->GameTick(); // NOLINT(clang-analyzer-unix.Malloc) if(!m_ReloadTimer) { diff --git a/src/game/client/prediction/entities/laser.cpp b/src/game/client/prediction/entities/laser.cpp index 0560643c68b..1f377192a18 100644 --- a/src/game/client/prediction/entities/laser.cpp +++ b/src/game/client/prediction/entities/laser.cpp @@ -20,7 +20,6 @@ CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEner m_Dir = Direction; m_Bounces = 0; m_EvalTick = 0; - m_WasTele = false; m_Type = Type; m_ZeroEnergyBounceInLastTick = false; m_TuneZone = GameWorld()->m_WorldConfig.m_UseTuneZones ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0; @@ -34,7 +33,7 @@ bool CLaser::HitCharacter(vec2 From, vec2 To) vec2 At; CCharacter *pOwnerChar = GameWorld()->GetCharacterByID(m_Owner); CCharacter *pHit; - bool DontHitSelf = (g_Config.m_SvOldLaser || !GameWorld()->m_WorldConfig.m_IsDDRace) || (m_Bounces == 0 && !m_WasTele); + bool DontHitSelf = (g_Config.m_SvOldLaser || !GameWorld()->m_WorldConfig.m_IsDDRace) || (m_Bounces == 0); if(pOwnerChar ? (!pOwnerChar->LaserHitDisabled() && m_Type == WEAPON_LASER) || (!pOwnerChar->ShotgunHitDisabled() && m_Type == WEAPON_SHOTGUN) : g_Config.m_SvHit) pHit = GameWorld()->IntersectCharacter(m_Pos, To, 0.f, At, DontHitSelf ? pOwnerChar : 0, m_Owner); @@ -102,13 +101,6 @@ void CLaser::DoBounce() int Res; int z; - if(m_WasTele) - { - m_PrevPos = m_TelePos; - m_Pos = m_TelePos; - m_TelePos = vec2(0, 0); - } - vec2 To = m_Pos + m_Dir * m_Energy; Res = Collision()->IntersectLineTeleWeapon(m_Pos, To, &Coltile, &To, &z); @@ -151,7 +143,6 @@ void CLaser::DoBounce() m_ZeroEnergyBounceInLastTick = Distance == 0.0f; m_Bounces++; - m_WasTele = false; int BounceNum = GetTuning(m_TuneZone)->m_LaserBounceNum; diff --git a/src/game/client/prediction/entities/laser.h b/src/game/client/prediction/entities/laser.h index 51570cf3fc2..3bf8e273732 100644 --- a/src/game/client/prediction/entities/laser.h +++ b/src/game/client/prediction/entities/laser.h @@ -30,8 +30,6 @@ class CLaser : public CEntity private: vec2 m_From; vec2 m_Dir; - vec2 m_TelePos; - bool m_WasTele; float m_Energy; int m_Bounces; int m_EvalTick; diff --git a/src/game/client/prediction/gameworld.cpp b/src/game/client/prediction/gameworld.cpp index eddc4e761e0..58f9eeb6979 100644 --- a/src/game/client/prediction/gameworld.cpp +++ b/src/game/client/prediction/gameworld.cpp @@ -593,7 +593,6 @@ void CGameWorld::CopyWorld(CGameWorld *pFrom) pFrom->m_pChild = this; m_GameTick = pFrom->m_GameTick; - m_GameTickSpeed = pFrom->m_GameTickSpeed; m_pCollision = pFrom->m_pCollision; m_WorldConfig = pFrom->m_WorldConfig; for(int i = 0; i < 2; i++) diff --git a/src/game/client/prediction/gameworld.h b/src/game/client/prediction/gameworld.h index 32d00dd78a7..fbb63ad9b05 100644 --- a/src/game/client/prediction/gameworld.h +++ b/src/game/client/prediction/gameworld.h @@ -51,12 +51,11 @@ class CGameWorld std::vector IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, const CEntity *pNotThis = nullptr); int m_GameTick; - int m_GameTickSpeed; CCollision *m_pCollision; // getter for server variables int GameTick() { return m_GameTick; } - int GameTickSpeed() { return m_GameTickSpeed; } + int GameTickSpeed() { return SERVER_TICK_SPEED; } CCollision *Collision() { return m_pCollision; } CTeamsCore *Teams() { return &m_Teams; } std::vector &Switchers() { return m_Core.m_vSwitchers; } diff --git a/src/game/client/ui_scrollregion.cpp b/src/game/client/ui_scrollregion.cpp index 37ec86143b7..2d3303d4f0f 100644 --- a/src/game/client/ui_scrollregion.cpp +++ b/src/game/client/ui_scrollregion.cpp @@ -22,6 +22,7 @@ CScrollRegion::CScrollRegion() m_AnimInitScrollY = 0.0f; m_AnimTargetScrollY = 0.0f; + m_SliderGrabPos = 0.0f; m_ContentScrollOff = vec2(0.0f, 0.0f); m_Params = CScrollRegionParams(); } @@ -146,8 +147,8 @@ void CScrollRegion::End() if(UI()->CheckActiveItem(pID) && UI()->MouseButton(0)) { float MouseY = UI()->MouseY(); - m_ScrollY += (MouseY - (Slider.y + m_SliderGrabPos.y)) / MaxSlider * MaxScroll; - m_SliderGrabPos.y = clamp(m_SliderGrabPos.y, 0.0f, SliderHeight); + m_ScrollY += (MouseY - (Slider.y + m_SliderGrabPos)) / MaxSlider * MaxScroll; + m_SliderGrabPos = clamp(m_SliderGrabPos, 0.0f, SliderHeight); m_AnimTargetScrollY = m_ScrollY; m_AnimTime = 0.0f; Grabbed = true; @@ -159,7 +160,7 @@ void CScrollRegion::End() if(!UI()->CheckActiveItem(pID) && UI()->MouseButtonClicked(0)) { UI()->SetActiveItem(pID); - m_SliderGrabPos.y = UI()->MouseY() - Slider.y; + m_SliderGrabPos = UI()->MouseY() - Slider.y; m_AnimTargetScrollY = m_ScrollY; m_AnimTime = 0.0f; m_Params.m_Active = true; @@ -170,7 +171,7 @@ void CScrollRegion::End() m_ScrollY += (UI()->MouseY() - (Slider.y + Slider.h / 2.0f)) / MaxSlider * MaxScroll; UI()->SetHotItem(pID); UI()->SetActiveItem(pID); - m_SliderGrabPos.y = Slider.h / 2.0f; + m_SliderGrabPos = Slider.h / 2.0f; m_AnimTargetScrollY = m_ScrollY; m_AnimTime = 0.0f; m_Params.m_Active = true; diff --git a/src/game/client/ui_scrollregion.h b/src/game/client/ui_scrollregion.h index f196fb61c21..2a601be5341 100644 --- a/src/game/client/ui_scrollregion.h +++ b/src/game/client/ui_scrollregion.h @@ -117,7 +117,7 @@ class CScrollRegion : private CUIElementBase CUIRect m_ClipRect; CUIRect m_RailRect; CUIRect m_LastAddedRect; // saved for ScrollHere() - vec2 m_SliderGrabPos; // where did user grab the slider + float m_SliderGrabPos; // where did user grab the slider vec2 m_ContentScrollOff; CScrollRegionParams m_Params; diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 767140568cf..5888c7fa4af 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -8062,6 +8062,40 @@ bool CEditor::Append(const char *pFileName, int StorageType) if(!NewMap.Load(pFileName, StorageType, std::move(ErrorHandler))) return false; + static const auto &&s_ReplaceIndex = [](int ToReplace, int ReplaceWith) { + return [ToReplace, ReplaceWith](int *pIndex) { + if(*pIndex == ToReplace) + *pIndex = ReplaceWith; + }; + }; + + //Transfer non-duplicate images + for(auto NewMapIt = NewMap.m_vpImages.begin(); NewMapIt != NewMap.m_vpImages.end(); ++NewMapIt) + { + auto pNewImage = *NewMapIt; + auto NameIsTaken = [pNewImage](const std::shared_ptr &OtherImage) { return str_comp(pNewImage->m_aName, OtherImage->m_aName) == 0; }; + auto MatchInCurrentMap = std::find_if(begin(m_Map.m_vpImages), end(m_Map.m_vpImages), NameIsTaken); + + const bool IsDuplicate = MatchInCurrentMap != std::end(m_Map.m_vpImages); + const int IndexToReplace = NewMapIt - NewMap.m_vpImages.begin(); + + if(IsDuplicate) + { + const int IndexToReplaceWith = MatchInCurrentMap - m_Map.m_vpImages.begin(); + + dbg_msg("editor", "map contains image %s already, removing duplicate", pNewImage->m_aName); + + //In the new map, replace the index of the duplicate image to the index of the same in the current map. + NewMap.ModifyImageIndex(s_ReplaceIndex(IndexToReplace, IndexToReplaceWith)); + } + else + { + NewMap.ModifyImageIndex(s_ReplaceIndex(IndexToReplace, m_Map.m_vpImages.size())); + m_Map.m_vpImages.push_back(pNewImage); + } + } + NewMap.m_vpImages.clear(); + // modify indices static const auto &&s_ModifyAddIndex = [](int AddAmount) { return [AddAmount](int *pIndex) { @@ -8069,15 +8103,10 @@ bool CEditor::Append(const char *pFileName, int StorageType) *pIndex += AddAmount; }; }; - NewMap.ModifyImageIndex(s_ModifyAddIndex(m_Map.m_vpImages.size())); + NewMap.ModifySoundIndex(s_ModifyAddIndex(m_Map.m_vpSounds.size())); NewMap.ModifyEnvelopeIndex(s_ModifyAddIndex(m_Map.m_vpEnvelopes.size())); - // transfer images - for(const auto &pImage : NewMap.m_vpImages) - m_Map.m_vpImages.push_back(pImage); - NewMap.m_vpImages.clear(); - // transfer sounds for(const auto &pSound : NewMap.m_vpSounds) m_Map.m_vpSounds.push_back(pSound); diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index f12e8d5372c..740b924a6de 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -393,6 +393,7 @@ class CEditor : public IEditor m_QuadKnifeActive = false; m_QuadKnifeCount = 0; + mem_zero(m_aQuadKnifePoints, sizeof(m_aQuadKnifePoints)); m_CheckerTexture.Invalidate(); m_BackgroundTexture.Invalidate(); @@ -441,7 +442,7 @@ class CEditor : public IEditor bool (*pfnFunc)(const char *pFilename, int StorageType, void *pUser), void *pUser); struct SStringKeyComparator { - bool operator()(char const *pLhs, char const *pRhs) const + bool operator()(const char *pLhs, const char *pRhs) const { return str_comp(pLhs, pRhs) < 0; } diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 3cddb43215c..0dd22b9b0ea 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -280,15 +280,18 @@ CUI::EPopupMenuFunctionResult CEditor::PopupMenuSettings(void *pContext, CUIRect Selector.VSplitMid(&No, &Yes); pEditor->UI()->DoLabel(&Label, "Allow unused", 10.0f, TEXTALIGN_ML); - static int s_ButtonNo = 0; - static int s_ButtonYes = 0; - if(pEditor->DoButton_ButtonDec(&s_ButtonNo, "No", !pEditor->m_AllowPlaceUnusedTiles, &No, 0, "[ctrl+u] Disallow placing unused tiles")) - { - pEditor->m_AllowPlaceUnusedTiles = false; - } - if(pEditor->DoButton_ButtonInc(&s_ButtonYes, "Yes", pEditor->m_AllowPlaceUnusedTiles, &Yes, 0, "[ctrl+u] Allow placing unused tiles")) + if(pEditor->m_AllowPlaceUnusedTiles != -1) { - pEditor->m_AllowPlaceUnusedTiles = true; + static int s_ButtonNo = 0; + static int s_ButtonYes = 0; + if(pEditor->DoButton_ButtonDec(&s_ButtonNo, "No", !pEditor->m_AllowPlaceUnusedTiles, &No, 0, "[ctrl+u] Disallow placing unused tiles")) + { + pEditor->m_AllowPlaceUnusedTiles = false; + } + if(pEditor->DoButton_ButtonInc(&s_ButtonYes, "Yes", pEditor->m_AllowPlaceUnusedTiles, &Yes, 0, "[ctrl+u] Allow placing unused tiles")) + { + pEditor->m_AllowPlaceUnusedTiles = true; + } } } diff --git a/src/game/gamecore.cpp b/src/game/gamecore.cpp index 5dc1fd00262..409fa0780c0 100644 --- a/src/game/gamecore.cpp +++ b/src/game/gamecore.cpp @@ -79,10 +79,7 @@ void CCharacterCore::Init(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore m_Id = -1; // fail safe, if core's tuning didn't get updated at all, just fallback to world tuning. - if(m_pWorld) - m_Tuning = m_pWorld->m_aTuning[g_Config.m_ClDummy]; - - Reset(); + m_Tuning = m_pWorld->m_aTuning[g_Config.m_ClDummy]; } void CCharacterCore::SetCoreWorld(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore *pTeams) @@ -99,6 +96,7 @@ void CCharacterCore::Reset() m_NewHook = false; m_HookPos = vec2(0, 0); m_HookDir = vec2(0, 0); + m_HookTeleBase = vec2(0, 0); m_HookTick = 0; m_HookState = HOOK_IDLE; SetHookedPlayer(-1); diff --git a/src/game/gamecore.h b/src/game/gamecore.h index b9f6e9b2971..8c81c00bda9 100644 --- a/src/game/gamecore.h +++ b/src/game/gamecore.h @@ -45,7 +45,6 @@ class CTuningParams public: CTuningParams() { - const float TicksPerSecond = 50.0f; #define MACRO_TUNING_PARAM(Name, ScriptName, Value, Description) m_##Name.Set((int)((Value)*100.0f)); #include "tuning.h" #undef MACRO_TUNING_PARAM @@ -284,7 +283,6 @@ class CCharacterCore bool m_Reset; CCollision *Collision() { return m_pCollision; } - vec2 m_LastVel; int m_Colliding; bool m_LeftWall; diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp index 3a7702b2ef8..5253a2bc099 100644 --- a/src/game/server/ddracechat.cpp +++ b/src/game/server/ddracechat.cpp @@ -953,7 +953,7 @@ void CGameContext::UnlockTeam(int ClientID, int Team) void CGameContext::ConInviteTeam(IConsole::IResult *pResult, void *pUserData) { CGameContext *pSelf = (CGameContext *)pUserData; - CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController; + auto *pController = pSelf->m_pController; const char *pName = pResult->GetString(0); if(g_Config.m_SvTeam == SV_TEAM_FORBIDDEN || g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO) @@ -1004,10 +1004,10 @@ void CGameContext::ConInviteTeam(IConsole::IResult *pResult, void *pUserData) pSelf->m_apPlayers[pResult->m_ClientID]->m_LastInvited = pSelf->Server()->Tick(); char aBuf[512]; - str_format(aBuf, sizeof aBuf, "'%s' invited you to team %d.", pSelf->Server()->ClientName(pResult->m_ClientID), Team); + str_format(aBuf, sizeof(aBuf), "'%s' invited you to team %d.", pSelf->Server()->ClientName(pResult->m_ClientID), Team); pSelf->SendChatTarget(Target, aBuf); - str_format(aBuf, sizeof aBuf, "'%s' invited '%s' to your team.", pSelf->Server()->ClientName(pResult->m_ClientID), pSelf->Server()->ClientName(Target)); + str_format(aBuf, sizeof(aBuf), "'%s' invited '%s' to your team.", pSelf->Server()->ClientName(pResult->m_ClientID), pSelf->Server()->ClientName(Target)); pSelf->SendChatTeam(Team, aBuf); } else @@ -1017,7 +1017,7 @@ void CGameContext::ConInviteTeam(IConsole::IResult *pResult, void *pUserData) void CGameContext::ConJoinTeam(IConsole::IResult *pResult, void *pUserData) { CGameContext *pSelf = (CGameContext *)pUserData; - CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController; + auto *pController = pSelf->m_pController; if(!CheckClientID(pResult->m_ClientID)) return; @@ -1524,7 +1524,8 @@ void CGameContext::ConTele(IConsole::IResult *pResult, void *pUserData) vec2 Pos = pPlayer->m_ViewPos; if(pResult->NumArguments() == 0 && !pPlayer->IsPaused()) { - Pos = Pos + vec2(pChr->Core()->m_Input.m_TargetX, pChr->Core()->m_Input.m_TargetY); + vec2 ZoomScale = vec2(pPlayer->m_ShowDistance.x / 1400.0f, pPlayer->m_ShowDistance.y / 800.0f); + Pos = Pos + (vec2(pChr->Core()->m_Input.m_TargetX, pChr->Core()->m_Input.m_TargetY) * ZoomScale); } else if(pResult->NumArguments() > 0) { diff --git a/src/game/server/ddracecommands.cpp b/src/game/server/ddracecommands.cpp index 0630ad24e62..ae58a51ed83 100644 --- a/src/game/server/ddracecommands.cpp +++ b/src/game/server/ddracecommands.cpp @@ -407,8 +407,10 @@ void CGameContext::ConTeleport(IConsole::IResult *pResult, void *pUserData) { vec2 Pos = pSelf->m_apPlayers[TeleTo]->m_ViewPos; if(!pPlayer->IsPaused() && !pResult->NumArguments()) - Pos = Pos + vec2(pChr->Core()->m_Input.m_TargetX, pChr->Core()->m_Input.m_TargetY); - + { + vec2 ZoomScale = vec2(pPlayer->m_ShowDistance.x / 1400.0f, pPlayer->m_ShowDistance.y / 800.0f); + Pos = Pos + (vec2(pChr->Core()->m_Input.m_TargetX, pChr->Core()->m_Input.m_TargetY) * ZoomScale); + } pSelf->Teleport(pChr, Pos); pChr->UnFreeze(); pChr->Core()->m_Vel = vec2(0, 0); @@ -480,10 +482,10 @@ void CGameContext::VoteMute(const NETADDR *pAddr, int Secs, const char *pReason, char aBuf[128]; if(pReason[0]) - str_format(aBuf, sizeof aBuf, "'%s' banned '%s' for %d seconds from voting (%s)", + 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", + str_format(aBuf, sizeof(aBuf), "'%s' banned '%s' for %d seconds from voting", Server()->ClientName(AuthedID), pDisplayName, Secs); SendChat(-1, CHAT_ALL, aBuf); } @@ -499,7 +501,7 @@ bool CGameContext::VoteUnmute(const NETADDR *pAddr, const char *pDisplayName, in if(pDisplayName) { char aBuf[128]; - str_format(aBuf, sizeof aBuf, "'%s' unbanned '%s' from voting.", + str_format(aBuf, sizeof(aBuf), "'%s' unbanned '%s' from voting.", Server()->ClientName(AuthedID), pDisplayName); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "voteunmute", aBuf); } @@ -555,9 +557,9 @@ void CGameContext::Mute(const NETADDR *pAddr, int Secs, const char *pDisplayName char aBuf[128]; if(pReason[0]) - str_format(aBuf, sizeof aBuf, "'%s' has been muted for %d seconds (%s)", pDisplayName, Secs, pReason); + 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); + str_format(aBuf, sizeof(aBuf), "'%s' has been muted for %d seconds", pDisplayName, Secs); SendChat(-1, CHAT_ALL, aBuf); } @@ -598,7 +600,7 @@ void CGameContext::ConVoteUnmute(IConsole::IResult *pResult, void *pUserData) if(Found) { char aBuf[128]; - str_format(aBuf, sizeof aBuf, "'%s' unbanned '%s' from voting.", + 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); } @@ -624,7 +626,7 @@ void CGameContext::ConVoteMutes(IConsole::IResult *pResult, void *pUserData) 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, + 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); } @@ -742,7 +744,7 @@ void CGameContext::ConMutes(IConsole::IResult *pResult, void *pUserData) 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, + 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); } @@ -774,7 +776,7 @@ void CGameContext::ConModerate(IConsole::IResult *pResult, void *pUserData) void CGameContext::ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData) { CGameContext *pSelf = (CGameContext *)pUserData; - CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController; + auto *pController = pSelf->m_pController; if(g_Config.m_SvTeam == SV_TEAM_FORBIDDEN || g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO) { @@ -800,7 +802,7 @@ void CGameContext::ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData) void CGameContext::ConUninvite(IConsole::IResult *pResult, void *pUserData) { CGameContext *pSelf = (CGameContext *)pUserData; - CGameControllerDDRace *pController = (CGameControllerDDRace *)pSelf->m_pController; + auto *pController = pSelf->m_pController; pController->Teams().SetClientInvited(pResult->GetInteger(1), pResult->GetVictim(), false); } @@ -816,7 +818,7 @@ void CGameContext::ConFreezeHammer(IConsole::IResult *pResult, void *pUserData) return; char aBuf[128]; - str_format(aBuf, sizeof aBuf, "'%s' got freeze hammer!", + str_format(aBuf, sizeof(aBuf), "'%s' got freeze hammer!", pSelf->Server()->ClientName(Victim)); pSelf->SendChat(-1, CHAT_ALL, aBuf); @@ -834,7 +836,7 @@ void CGameContext::ConUnFreezeHammer(IConsole::IResult *pResult, void *pUserData return; char aBuf[128]; - str_format(aBuf, sizeof aBuf, "'%s' lost freeze hammer!", + str_format(aBuf, sizeof(aBuf), "'%s' lost freeze hammer!", pSelf->Server()->ClientName(Victim)); pSelf->SendChat(-1, CHAT_ALL, aBuf); @@ -878,7 +880,13 @@ void CGameContext::ConDrySave(IConsole::IResult *pResult, void *pUserData) void CGameContext::ConDumpAntibot(IConsole::IResult *pResult, void *pUserData) { CGameContext *pSelf = (CGameContext *)pUserData; - pSelf->Antibot()->Dump(); + pSelf->Antibot()->ConsoleCommand("dump"); +} + +void CGameContext::ConAntibot(IConsole::IResult *pResult, void *pUserData) +{ + CGameContext *pSelf = (CGameContext *)pUserData; + pSelf->Antibot()->ConsoleCommand(pResult->GetString(0)); } void CGameContext::ConDumpLog(IConsole::IResult *pResult, void *pUserData) @@ -906,9 +914,9 @@ void CGameContext::ConDumpLog(IConsole::IResult *pResult, void *pUserData) char aBuf[256]; if(pEntry->m_FromServer) - str_format(aBuf, sizeof aBuf, "%s, %d seconds ago", pEntry->m_aDescription, Seconds); + 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", + 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); } diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index fe25504d9bb..7f177835cc5 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -83,8 +83,7 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos) m_ReckoningTick = 0; m_SendCore = CCharacterCore(); - m_ReckoningCore = m_Core; - m_ReckoningCore.SetCoreWorld(nullptr, Collision(), nullptr); + m_ReckoningCore = CCharacterCore(); GameServer()->m_World.InsertEntity(this); m_Alive = true; @@ -526,7 +525,7 @@ void CCharacter::FireWeapon() MouseTarget //InitDir ); - GameServer()->CreateSound(m_Pos, SOUND_GUN_FIRE, TeamMask()); + GameServer()->CreateSound(m_Pos, SOUND_GUN_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) } } break; @@ -540,7 +539,7 @@ void CCharacter::FireWeapon() LaserReach = TuningList()[m_TuneZone].m_LaserReach; new CLaser(&GameServer()->m_World, m_Pos, Direction, LaserReach, m_pPlayer->GetCID(), WEAPON_SHOTGUN); - GameServer()->CreateSound(m_Pos, SOUND_SHOTGUN_FIRE, TeamMask()); + GameServer()->CreateSound(m_Pos, SOUND_SHOTGUN_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) } break; @@ -578,7 +577,7 @@ void CCharacter::FireWeapon() LaserReach = TuningList()[m_TuneZone].m_LaserReach; new CLaser(GameWorld(), m_Pos, Direction, LaserReach, m_pPlayer->GetCID(), WEAPON_LASER); - GameServer()->CreateSound(m_Pos, SOUND_LASER_FIRE, TeamMask()); + GameServer()->CreateSound(m_Pos, SOUND_LASER_FIRE, TeamMask()); // NOLINT(clang-analyzer-unix.Malloc) } break; @@ -790,6 +789,9 @@ void CCharacter::TickDeferred() { // advance the dummy { + CWorldCore TempWorld; + m_ReckoningCore.Init(&TempWorld, Collision(), &Teams()->m_Core, m_pTeleOuts); + m_ReckoningCore.m_Id = m_pPlayer->GetCID(); m_ReckoningCore.Tick(false); m_ReckoningCore.Move(); m_ReckoningCore.Quantize(); @@ -878,8 +880,6 @@ void CCharacter::TickDeferred() m_ReckoningTick = Server()->Tick(); m_SendCore = m_Core; m_ReckoningCore = m_Core; - m_ReckoningCore.SetCoreWorld(nullptr, Collision(), nullptr); - m_ReckoningCore.m_Tuning = CTuningParams(); m_Core.m_Reset = false; } } @@ -1060,7 +1060,7 @@ void CCharacter::SnapCharacter(int SnappingClient, int ID) if(Emote == EMOTE_NORMAL) { - if(250 - ((Server()->Tick() - m_LastAction) % (250)) < 5) + if(5 * Server()->TickSpeed() - ((Server()->Tick() - m_LastAction) % (5 * Server()->TickSpeed())) < 5) Emote = EMOTE_BLINK; } diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 89dc031c4a9..8f984b77015 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -203,7 +203,6 @@ class CCharacter : public CEntity int m_MoveRestrictions; - vec2 m_Intersection; int64_t m_LastStartWarning; int64_t m_LastRescue; bool m_LastRefillJumps; diff --git a/src/game/server/entities/dragger.cpp b/src/game/server/entities/dragger.cpp index a455c302993..e22800187ca 100644 --- a/src/game/server/entities/dragger.cpp +++ b/src/game/server/entities/dragger.cpp @@ -16,6 +16,7 @@ CDragger::CDragger(CGameWorld *pGameWorld, vec2 Pos, float Strength, bool IgnoreWalls, int Layer, int Number) : CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER) { + m_Core = vec2(0.0f, 0.0f); m_Pos = Pos; m_Strength = Strength; m_IgnoreWalls = IgnoreWalls; diff --git a/src/game/server/entities/gun.cpp b/src/game/server/entities/gun.cpp index aa77858c3a1..5c03604d638 100644 --- a/src/game/server/entities/gun.cpp +++ b/src/game/server/entities/gun.cpp @@ -16,6 +16,7 @@ CGun::CGun(CGameWorld *pGameWorld, vec2 Pos, bool Freeze, bool Explosive, int Layer, int Number) : CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER) { + m_Core = vec2(0.0f, 0.0f); m_Pos = Pos; m_Freeze = Freeze; m_Explosive = Explosive; diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp index e0fd0e578fb..2907d5b9589 100644 --- a/src/game/server/entities/laser.cpp +++ b/src/game/server/entities/laser.cpp @@ -20,6 +20,7 @@ CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEner m_Dir = Direction; m_Bounces = 0; m_EvalTick = 0; + m_TelePos = vec2(0, 0); m_WasTele = false; m_Type = Type; m_TeleportCancelled = false; diff --git a/src/game/server/entities/light.cpp b/src/game/server/entities/light.cpp index 8a15cdfdbab..42aea3f952f 100644 --- a/src/game/server/entities/light.cpp +++ b/src/game/server/entities/light.cpp @@ -15,6 +15,8 @@ CLight::CLight(CGameWorld *pGameWorld, vec2 Pos, float Rotation, int Length, int Layer, int Number) : CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER) { + m_To = vec2(0.0f, 0.0f); + m_Core = vec2(0.0f, 0.0f); m_Layer = Layer; m_Number = Number; m_Tick = (Server()->TickSpeed() * 0.15f); diff --git a/src/game/server/entities/pickup.cpp b/src/game/server/entities/pickup.cpp index 0e234f5fec1..6b599a08e56 100644 --- a/src/game/server/entities/pickup.cpp +++ b/src/game/server/entities/pickup.cpp @@ -15,6 +15,7 @@ static constexpr int gs_PickupPhysSize = 14; CPickup::CPickup(CGameWorld *pGameWorld, int Type, int SubType, int Layer, int Number) : CEntity(pGameWorld, CGameWorld::ENTTYPE_PICKUP, vec2(0, 0), gs_PickupPhysSize) { + m_Core = vec2(0.0f, 0.0f); m_Type = Type; m_Subtype = SubType; diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 9cc1755afac..154d12c902c 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -30,6 +30,7 @@ #include "entities/character.h" #include "gamemodes/DDRace.h" +#include "gamemodes/mod.h" #include "player.h" #include "score.h" @@ -569,7 +570,7 @@ void CGameContext::SendChat(int ChatterClientID, int Team, const char *pText, in Server()->SendPackMsg(&Msg, MSGFLAG_VITAL | MSGFLAG_NORECORD, i); } - str_format(aBuf, sizeof aBuf, "Chat: %s", aText); + str_format(aBuf, sizeof(aBuf), "Chat: %s", aText); LogEvent(aBuf, ChatterClientID); } else @@ -1194,21 +1195,6 @@ void CGameContext::OnTick() m_SqlRandomMapResult = nullptr; } -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - for(int i = 0; i < g_Config.m_DbgDummies; i++) - { - if(m_apPlayers[MAX_CLIENTS - i - 1]) - { - CNetObj_PlayerInput Input = {0}; - Input.m_Direction = (i & 1) ? -1 : 1; - m_apPlayers[MAX_CLIENTS - i - 1]->OnPredictedInput(&Input); - } - } - } -#endif - // Record player position at the end of the tick if(m_TeeHistorianActive) { @@ -1557,7 +1543,7 @@ void CGameContext::OnClientEnter(int ClientID) char aBuf[128]; NETADDR Addr; Server()->GetClientAddr(ClientID, &Addr); - str_format(aBuf, sizeof aBuf, "This server has an initial chat delay, you will need to wait %d seconds before talking.", g_Config.m_SvChatInitialDelay); + str_format(aBuf, sizeof(aBuf), "This server has an initial chat delay, you will need to wait %d seconds before talking.", g_Config.m_SvChatInitialDelay); SendChatTarget(ClientID, aBuf); Mute(&Addr, g_Config.m_SvChatInitialDelay, Server()->ClientName(ClientID), "Initial chat delay", true); } @@ -1614,14 +1600,6 @@ void CGameContext::OnClientConnected(int ClientID, void *pData) m_apPlayers[ClientID]->SetInitialAfk(Afk); NextUniqueClientID += 1; -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - if(ClientID >= MAX_CLIENTS - g_Config.m_DbgDummies) - return; - } -#endif - SendMotd(ClientID); SendSettings(ClientID); @@ -3471,6 +3449,7 @@ void CGameContext::OnConsoleInit() Console()->Register("vote", "r['yes'|'no']", CFGFLAG_SERVER, ConVote, this, "Force a vote to yes/no"); Console()->Register("votes", "?i[page]", CFGFLAG_SERVER, ConVotes, this, "Show all votes (page 0 by default, 20 entries per page)"); Console()->Register("dump_antibot", "", CFGFLAG_SERVER, ConDumpAntibot, this, "Dumps the antibot status"); + Console()->Register("antibot", "r[command]", CFGFLAG_SERVER, ConAntibot, this, "Sends a command to the antibot"); Console()->Chain("sv_motd", ConchainSpecialMotdupdate, this); @@ -3592,7 +3571,10 @@ void CGameContext::OnInit(const void *pPersistentData) } } - m_pController = new CGameControllerDDRace(this); + if(!str_comp(Config()->m_SvGametype, "mod")) + m_pController = new CGameControllerMod(this); + else + m_pController = new CGameControllerDDRace(this); const char *pCensorFilename = "censorlist.txt"; IOHANDLE File = Storage()->OpenFile(pCensorFilename, IOFLAG_READ | IOFLAG_SKIP_BOM, IStorage::TYPE_ALL); @@ -3697,16 +3679,6 @@ void CGameContext::OnInit(const void *pPersistentData) Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "git-revision", GIT_SHORTREV_HASH); m_pAntibot->RoundStart(this); - -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - for(int i = 0; i < g_Config.m_DbgDummies; i++) - { - OnClientConnected(MAX_CLIENTS - i - 1, 0); - } - } -#endif } void CGameContext::CreateAllEntities(bool Initial) @@ -4198,9 +4170,9 @@ bool CGameContext::ProcessSpamProtection(int ClientID, bool RespectChatInitialDe { char aBuf[128]; if(Muted.m_InitialChatDelay) - str_format(aBuf, sizeof aBuf, "This server has an initial chat delay, you will be able to talk in %d seconds.", Expires); + str_format(aBuf, sizeof(aBuf), "This server has an initial chat delay, you will be able to talk in %d seconds.", Expires); else - str_format(aBuf, sizeof aBuf, "You are not permitted to talk for the next %d seconds.", Expires); + str_format(aBuf, sizeof(aBuf), "You are not permitted to talk for the next %d seconds.", Expires); SendChatTarget(ClientID, aBuf); return true; } diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 70b7878380e..02c53a352a7 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -132,6 +132,7 @@ class CGameContext : public IGameServer static void ConVoteNo(IConsole::IResult *pResult, void *pUserData); static void ConDrySave(IConsole::IResult *pResult, void *pUserData); static void ConDumpAntibot(IConsole::IResult *pResult, void *pUserData); + static void ConAntibot(IConsole::IResult *pResult, void *pUserData); static void ConchainSpecialMotdupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainSettingUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConDumpLog(IConsole::IResult *pResult, void *pUserData); diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index 728861dfbc8..270dc6a0edf 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "gamecontext.h" @@ -19,7 +20,7 @@ #include "entities/projectile.h" IGameController::IGameController(class CGameContext *pGameServer) : - m_Teams(pGameServer) + m_Teams(pGameServer), m_pLoadBestTimeResult(nullptr) { m_pGameServer = pGameServer; m_pConfig = m_pGameServer->Config(); @@ -52,13 +53,6 @@ void IGameController::DoActivityCheck() for(int i = 0; i < MAX_CLIENTS; ++i) { -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - if(i >= MAX_CLIENTS - g_Config.m_DbgDummies) - break; - } -#endif if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && Server()->GetAuthedState(i) == AUTHED_NO) { if(Server()->Tick() > GameServer()->m_apPlayers[i]->m_LastActionTick + g_Config.m_SvInactiveKickTime * Server()->TickSpeed() * 60) @@ -384,11 +378,11 @@ bool IGameController::OnEntity(int Index, int x, int y, int Layer, int Flags, bo new CGun(&GameServer()->m_World, Pos, false, false, Layer, Number); } - if(Type != -1) + if(Type != -1) // NOLINT(clang-analyzer-unix.Malloc) { CPickup *pPickup = new CPickup(&GameServer()->m_World, Type, SubType, Layer, Number); pPickup->m_Pos = Pos; - return true; + return true; // NOLINT(clang-analyzer-unix.Malloc) } return false; @@ -537,6 +531,23 @@ void IGameController::Tick() } } + if(m_pLoadBestTimeResult != nullptr && m_pLoadBestTimeResult->m_Completed) + { + if(m_pLoadBestTimeResult->m_Success) + { + m_CurrentRecord = m_pLoadBestTimeResult->m_CurrentRecord; + + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetClientVersion() >= VERSION_DDRACE) + { + GameServer()->SendRecord(i); + } + } + } + m_pLoadBestTimeResult = nullptr; + } + DoActivityCheck(); } @@ -630,7 +641,7 @@ void IGameController::Snap(int SnappingClient) return; pRaceData->m_BestTime = round_to_int(m_CurrentRecord * 1000); - pRaceData->m_Precision = 0; + pRaceData->m_Precision = 2; pRaceData->m_RaceFlags = protocol7::RACEFLAG_HIDE_KILLMSG | protocol7::RACEFLAG_KEEP_WANTED_WEAPON; } @@ -731,8 +742,10 @@ int IGameController::ClampTeam(int Team) CClientMask IGameController::GetMaskForPlayerWorldEvent(int Asker, int ExceptID) { - // Send all world events to everyone by default - return CClientMask().set().reset(ExceptID); + if(Asker == -1) + return CClientMask().set().reset(ExceptID); + + return Teams().TeamMask(GameServer()->GetDDRaceTeam(Asker), ExceptID, Asker); } void IGameController::InitTeleporter() diff --git a/src/game/server/gamecontroller.h b/src/game/server/gamecontroller.h index a0cc1f00d28..81c3fa33b89 100644 --- a/src/game/server/gamecontroller.h +++ b/src/game/server/gamecontroller.h @@ -11,6 +11,8 @@ #include #include +struct CScoreLoadBestTimeResult; + /* Class: Game Controller Controls the main game logic. Keeping track of team and player score, @@ -146,7 +148,7 @@ class IGameController virtual bool CanJoinTeam(int Team, int NotThisID); int ClampTeam(int Team); - virtual CClientMask GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1); + CClientMask GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1); virtual void InitTeleporter(); // DDRace @@ -155,6 +157,7 @@ class IGameController std::map> m_TeleOuts; std::map> m_TeleCheckOuts; CGameTeams &Teams() { return m_Teams; } + std::shared_ptr m_pLoadBestTimeResult; }; #endif diff --git a/src/game/server/gamemodes/DDRace.cpp b/src/game/server/gamemodes/DDRace.cpp index 2d287d611cf..48a6d71bd86 100644 --- a/src/game/server/gamemodes/DDRace.cpp +++ b/src/game/server/gamemodes/DDRace.cpp @@ -15,7 +15,7 @@ #define TEST_TYPE_NAME "TestDDraceNetwork" CGameControllerDDRace::CGameControllerDDRace(class CGameContext *pGameServer) : - IGameController(pGameServer), m_pLoadBestTimeResult(nullptr) + IGameController(pGameServer) { m_pGameType = g_Config.m_SvTestingCommands ? TEST_TYPE_NAME : GAME_TYPE_NAME; } @@ -159,23 +159,6 @@ void CGameControllerDDRace::Tick() IGameController::Tick(); Teams().ProcessSaveTeam(); Teams().Tick(); - - if(m_pLoadBestTimeResult != nullptr && m_pLoadBestTimeResult->m_Completed) - { - if(m_pLoadBestTimeResult->m_Success) - { - m_CurrentRecord = m_pLoadBestTimeResult->m_CurrentRecord; - - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetClientVersion() >= VERSION_DDRACE) - { - GameServer()->SendRecord(i); - } - } - } - m_pLoadBestTimeResult = nullptr; - } } void CGameControllerDDRace::DoTeamChange(class CPlayer *pPlayer, int Team, bool DoChatMsg) @@ -200,11 +183,3 @@ void CGameControllerDDRace::DoTeamChange(class CPlayer *pPlayer, int Team, bool IGameController::DoTeamChange(pPlayer, Team, DoChatMsg); } - -CClientMask CGameControllerDDRace::GetMaskForPlayerWorldEvent(int Asker, int ExceptID) -{ - if(Asker == -1) - return CClientMask().set().reset(ExceptID); - - return Teams().TeamMask(GameServer()->GetDDRaceTeam(Asker), ExceptID, Asker); -} diff --git a/src/game/server/gamemodes/DDRace.h b/src/game/server/gamemodes/DDRace.h index fb7428114ce..17626f26a3d 100644 --- a/src/game/server/gamemodes/DDRace.h +++ b/src/game/server/gamemodes/DDRace.h @@ -4,7 +4,6 @@ #include -struct CScoreLoadBestTimeResult; class CGameControllerDDRace : public IGameController { public: @@ -23,9 +22,5 @@ class CGameControllerDDRace : public IGameController void Tick() override; void DoTeamChange(class CPlayer *pPlayer, int Team, bool DoChatMsg = true) override; - - CClientMask GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1) override; - - std::shared_ptr m_pLoadBestTimeResult; }; #endif // GAME_SERVER_GAMEMODES_DDRACE_H diff --git a/src/game/server/gamemodes/mod.cpp b/src/game/server/gamemodes/mod.cpp new file mode 100644 index 00000000000..1c6fc97f765 --- /dev/null +++ b/src/game/server/gamemodes/mod.cpp @@ -0,0 +1,24 @@ +#include "mod.h" + +// Exchange this to a string that identifies your game mode. +// DM, TDM and CTF are reserved for teeworlds original modes. +// DDraceNetwork and TestDDraceNetwork are used by DDNet. +#define GAME_TYPE_NAME "Mod" +#define TEST_TYPE_NAME "TestMod" + +CGameControllerMod::CGameControllerMod(class CGameContext *pGameServer) : + IGameController(pGameServer) +{ + m_pGameType = g_Config.m_SvTestingCommands ? TEST_TYPE_NAME : GAME_TYPE_NAME; + + //m_GameFlags = GAMEFLAG_TEAMS; // GAMEFLAG_TEAMS makes it a two-team gamemode +} + +CGameControllerMod::~CGameControllerMod() = default; + +void CGameControllerMod::Tick() +{ + // this is the main part of the gamemode, this function is run every tick + + IGameController::Tick(); +} diff --git a/src/game/server/gamemodes/mod.h b/src/game/server/gamemodes/mod.h new file mode 100644 index 00000000000..f74d5306a81 --- /dev/null +++ b/src/game/server/gamemodes/mod.h @@ -0,0 +1,14 @@ +#ifndef GAME_SERVER_GAMEMODES_MOD_H +#define GAME_SERVER_GAMEMODES_MOD_H + +#include + +class CGameControllerMod : public IGameController +{ +public: + CGameControllerMod(class CGameContext *pGameServer); + ~CGameControllerMod(); + + void Tick() override; +}; +#endif // GAME_SERVER_GAMEMODES_MOD_H diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp index c35359a8fbd..9247cca8838 100644 --- a/src/game/server/gameworld.cpp +++ b/src/game/server/gameworld.cpp @@ -349,7 +349,6 @@ std::vector CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1 float Len = distance(pChr->m_Pos, IntersectPos); if(Len < pChr->m_ProximityRadius + Radius) { - pChr->m_Intersection = IntersectPos; vpCharacters.push_back(pChr); } } diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index f5cc9e945d9..de3ae840eb5 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -169,14 +169,7 @@ void CPlayer::Tick() m_ScoreFinishResult = nullptr; } - bool ClientIngame = Server()->ClientIngame(m_ClientID); -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies && m_ClientID >= MAX_CLIENTS - g_Config.m_DbgDummies) - { - ClientIngame = true; - } -#endif - if(!ClientIngame) + if(!Server()->ClientIngame(m_ClientID)) return; if(m_ChatScore > 0) @@ -302,11 +295,8 @@ void CPlayer::PostTick() void CPlayer::PostPostTick() { -#ifdef CONF_DEBUG - if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS - g_Config.m_DbgDummies) -#endif - if(!Server()->ClientIngame(m_ClientID)) - return; + if(!Server()->ClientIngame(m_ClientID)) + return; if(!GameServer()->m_World.m_Paused && !m_pCharacter && m_Spawning && m_WeakHookSpawn) TryRespawn(); @@ -314,11 +304,8 @@ void CPlayer::PostPostTick() void CPlayer::Snap(int SnappingClient) { -#ifdef CONF_DEBUG - if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS - g_Config.m_DbgDummies) -#endif - if(!Server()->ClientIngame(m_ClientID)) - return; + if(!Server()->ClientIngame(m_ClientID)) + return; int id = m_ClientID; if(!Server()->Translate(id, SnappingClient)) @@ -392,7 +379,7 @@ void CPlayer::Snap(int SnappingClient) pPlayerInfo->m_PlayerFlags |= protocol7::PLAYERFLAG_ADMIN; // Times are in milliseconds for 0.7 - pPlayerInfo->m_Score = Score == -9999 ? -1 : -Score * 1000; + pPlayerInfo->m_Score = m_Score.has_value() ? GameServer()->Score()->PlayerData(id)->m_BestTime * 1000 : -1; pPlayerInfo->m_Latency = Latency; } @@ -578,6 +565,13 @@ CCharacter *CPlayer::GetCharacter() return 0; } +const CCharacter *CPlayer::GetCharacter() const +{ + if(m_pCharacter && m_pCharacter->IsAlive()) + return m_pCharacter; + return 0; +} + void CPlayer::KillCharacter(int Weapon, bool SendKillMsg) { if(m_pCharacter) diff --git a/src/game/server/player.h b/src/game/server/player.h index d051d179c88..1f050cb7802 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -64,6 +64,7 @@ class CPlayer void KillCharacter(int Weapon = WEAPON_GAME, bool SendKillMsg = true); CCharacter *GetCharacter(); + const CCharacter *GetCharacter() const; void SpectatePlayerName(const char *pName); diff --git a/src/game/server/score.cpp b/src/game/server/score.cpp index 139bf6e5127..b70fe89026d 100644 --- a/src/game/server/score.cpp +++ b/src/game/server/score.cpp @@ -110,11 +110,11 @@ CScore::CScore(CGameContext *pGameServer, CDbConnectionPool *pPool) : void CScore::LoadBestTime() { - if(((CGameControllerDDRace *)(m_pGameServer->m_pController))->m_pLoadBestTimeResult) + if(m_pGameServer->m_pController->m_pLoadBestTimeResult) return; // already in progress auto LoadBestTimeResult = std::make_shared(); - ((CGameControllerDDRace *)(m_pGameServer->m_pController))->m_pLoadBestTimeResult = LoadBestTimeResult; + m_pGameServer->m_pController->m_pLoadBestTimeResult = LoadBestTimeResult; auto Tmp = std::make_unique(LoadBestTimeResult); str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap)); @@ -281,7 +281,7 @@ void CScore::SaveTeam(int ClientID, const char *pCode, const char *pServer) { if(RateLimitPlayer(ClientID)) return; - auto *pController = ((CGameControllerDDRace *)(GameServer()->m_pController)); + auto *pController = GameServer()->m_pController; int Team = pController->Teams().m_Core.Team(ClientID); if(pController->Teams().GetSaving(Team)) return; @@ -326,7 +326,7 @@ void CScore::LoadTeam(const char *pCode, int ClientID) { if(RateLimitPlayer(ClientID)) return; - auto *pController = ((CGameControllerDDRace *)(GameServer()->m_pController)); + auto *pController = GameServer()->m_pController; int Team = pController->Teams().m_Core.Team(ClientID); if(pController->Teams().GetSaving(Team)) return; diff --git a/src/game/server/teehistorian.cpp b/src/game/server/teehistorian.cpp index d0bc838db14..083ccd65d99 100644 --- a/src/game/server/teehistorian.cpp +++ b/src/game/server/teehistorian.cpp @@ -181,7 +181,6 @@ void CTeeHistorian::WriteHeader(const CGameInfo *pGameInfo) First = true; - const float TicksPerSecond = 50.0f; #define MACRO_TUNING_PARAM(Name, ScriptName, Value, Description) \ if(pGameInfo->m_pTuning->m_##Name.Get() != (int)((Value)*100)) \ { \ diff --git a/src/game/tuning.h b/src/game/tuning.h index 887f43f9790..ac6340012e1 100644 --- a/src/game/tuning.h +++ b/src/game/tuning.h @@ -5,11 +5,11 @@ // physics tuning MACRO_TUNING_PARAM(GroundControlSpeed, ground_control_speed, 10.0f, "Max speed the tee can get on ground") -MACRO_TUNING_PARAM(GroundControlAccel, ground_control_accel, 100.0f / TicksPerSecond, "Acceleration speed on the ground") +MACRO_TUNING_PARAM(GroundControlAccel, ground_control_accel, 100.0f / SERVER_TICK_SPEED, "Acceleration speed on the ground") MACRO_TUNING_PARAM(GroundFriction, ground_friction, 0.5f, "Friction on the ground") MACRO_TUNING_PARAM(GroundJumpImpulse, ground_jump_impulse, 13.2f, "Impulse when jumping on ground") MACRO_TUNING_PARAM(AirJumpImpulse, air_jump_impulse, 12.0f, "Impulse when jumping in air") -MACRO_TUNING_PARAM(AirControlSpeed, air_control_speed, 250.0f / TicksPerSecond, "Max speed the tee can get in the air") +MACRO_TUNING_PARAM(AirControlSpeed, air_control_speed, 250.0f / SERVER_TICK_SPEED, "Max speed the tee can get in the air") MACRO_TUNING_PARAM(AirControlAccel, air_control_accel, 1.5f, "Acceleration speed in air") MACRO_TUNING_PARAM(AirFriction, air_friction, 0.95f, "Friction in the air") MACRO_TUNING_PARAM(HookLength, hook_length, 380.0f, "Length of the hook") diff --git a/src/game/variables.h b/src/game/variables.h index e3eb6cecbf3..d2d3ead0532 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -242,6 +242,7 @@ MACRO_CONFIG_INT(ClSkipStartMenu, cl_skip_start_menu, 0, 0, 1, CFGFLAG_CLIENT | // server MACRO_CONFIG_INT(SvWarmup, sv_warmup, 0, 0, 0, CFGFLAG_SERVER, "Number of seconds to do warmup before round starts") MACRO_CONFIG_STR(SvMotd, sv_motd, 900, "", CFGFLAG_SERVER, "Message of the day to display for the clients") +MACRO_CONFIG_STR(SvGametype, sv_gametype, 32, "ddnet", CFGFLAG_SAVE | CFGFLAG_SERVER, "Game type (ddnet, mod)") MACRO_CONFIG_INT(SvTournamentMode, sv_tournament_mode, 0, 0, 1, CFGFLAG_SERVER, "Tournament mode. When enabled, players joins the server as spectator") MACRO_CONFIG_INT(SvSpamprotection, sv_spamprotection, 1, 0, 1, CFGFLAG_SERVER, "Spam protection") @@ -284,8 +285,8 @@ MACRO_CONFIG_INT(ClVideoX264Crf, cl_video_crf, 18, 0, 51, CFGFLAG_CLIENT | CFGFL MACRO_CONFIG_INT(ClVideoX264Preset, cl_video_preset, 5, 0, 9, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Set preset when encode video with libx264, default is 5 (medium), 0 is ultrafast, 9 is placebo (the slowest, not recommend)") // debug -#ifdef CONF_DEBUG // this one can crash the server if not used correctly -MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "(Debug build only)") +#ifdef CONF_DEBUG +MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Add debug dummies to server (Debug build only)") #endif MACRO_CONFIG_INT(DbgTuning, dbg_tuning, 0, 0, 2, CFGFLAG_CLIENT, "Display information about the tuning parameters that affect the own player (0 = off, 1 = show changed, 2 = show all)") diff --git a/src/game/version.h b/src/game/version.h index bb8461f6049..dba4a386ad3 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -3,11 +3,11 @@ #ifndef GAME_VERSION_H #define GAME_VERSION_H #ifndef GAME_RELEASE_VERSION -#define GAME_RELEASE_VERSION "17.3" +#define GAME_RELEASE_VERSION "17.4" #endif #define GAME_VERSION "0.6.4, " GAME_RELEASE_VERSION #define GAME_NETVERSION "0.6 626fce9a778df4d4" -#define DDNET_VERSION_NUMBER 17030 +#define DDNET_VERSION_NUMBER 17040 extern const char *GIT_SHORTREV_HASH; #define GAME_NAME "DDNet" #endif diff --git a/src/test/memory.cpp b/src/test/memory.cpp new file mode 100644 index 00000000000..58e661c774b --- /dev/null +++ b/src/test/memory.cpp @@ -0,0 +1,187 @@ +#include + +#include + +static bool mem_is_null(const void *block, size_t size) +{ + const unsigned char *bytes = (const unsigned char *)block; + size_t i; + for(i = 0; i < size; i++) + { + if(bytes[i] != 0) + { + return false; + } + } + return true; +} + +TEST(Memory, BaseTypes) +{ + void *aVoid[123]; + secure_random_fill(aVoid, sizeof(aVoid)); + EXPECT_FALSE(mem_is_null(aVoid, sizeof(aVoid))); + mem_zero(&aVoid, sizeof(aVoid)); + EXPECT_TRUE(mem_is_null(aVoid, sizeof(aVoid))); + secure_random_fill(aVoid, sizeof(aVoid)); + EXPECT_FALSE(mem_is_null(aVoid, sizeof(aVoid))); + mem_zero(&aVoid[0], 123 * sizeof(void *)); + EXPECT_TRUE(mem_is_null(aVoid, sizeof(aVoid))); + + secure_random_fill(aVoid, sizeof(aVoid)); + EXPECT_FALSE(mem_is_null(aVoid, sizeof(aVoid))); + mem_zero(aVoid, sizeof(aVoid)); + EXPECT_TRUE(mem_is_null(aVoid, sizeof(aVoid))); + + int aInt[512]; + secure_random_fill(aInt, sizeof(aInt)); + EXPECT_FALSE(mem_is_null(aInt, sizeof(aInt))); + mem_zero(&aInt, sizeof(aInt)); + EXPECT_TRUE(mem_is_null(aInt, sizeof(aInt))); + secure_random_fill(aInt, sizeof(aInt)); + EXPECT_FALSE(mem_is_null(aInt, sizeof(aInt))); + mem_zero(&aInt[0], sizeof(aInt)); + EXPECT_TRUE(mem_is_null(aInt, sizeof(aInt))); + + secure_random_fill(aInt, sizeof(aInt)); + EXPECT_FALSE(mem_is_null(aInt, sizeof(aInt))); + mem_zero(aInt, sizeof(aInt)); + EXPECT_TRUE(mem_is_null(aInt, sizeof(aInt))); + + int *apInt[512]; + secure_random_fill(apInt, sizeof(apInt)); + EXPECT_FALSE(mem_is_null(apInt, sizeof(apInt))); + mem_zero(&apInt, sizeof(apInt)); + EXPECT_TRUE(mem_is_null(apInt, sizeof(apInt))); + + secure_random_fill(apInt, sizeof(apInt)); + EXPECT_FALSE(mem_is_null(apInt, sizeof(apInt))); + mem_zero(apInt, sizeof(apInt)); + EXPECT_TRUE(mem_is_null(apInt, sizeof(apInt))); + + int aaInt[10][20]; + secure_random_fill(aaInt, sizeof(aaInt)); + EXPECT_FALSE(mem_is_null(aaInt, sizeof(aaInt))); + mem_zero(&aaInt, sizeof(aaInt)); + EXPECT_TRUE(mem_is_null(aaInt, sizeof(aaInt))); + secure_random_fill(aaInt, sizeof(aaInt)); + EXPECT_FALSE(mem_is_null(aaInt, sizeof(aaInt))); + mem_zero(&aaInt[0], sizeof(aaInt)); + EXPECT_TRUE(mem_is_null(aaInt, sizeof(aaInt))); + secure_random_fill(aaInt, sizeof(aaInt)); + EXPECT_FALSE(mem_is_null(aaInt, sizeof(aaInt))); + mem_zero(&aaInt[0][0], sizeof(aaInt)); + EXPECT_TRUE(mem_is_null(aaInt, sizeof(aaInt))); + + secure_random_fill(aaInt, sizeof(aaInt)); + EXPECT_FALSE(mem_is_null(aaInt, sizeof(aaInt))); + mem_zero(aaInt, sizeof(aaInt)); + EXPECT_TRUE(mem_is_null(aaInt, sizeof(aaInt))); + secure_random_fill(aaInt, sizeof(aaInt)); + EXPECT_FALSE(mem_is_null(aaInt, sizeof(aaInt))); + mem_zero(aaInt[0], sizeof(aaInt)); + EXPECT_TRUE(mem_is_null(aaInt, sizeof(aaInt))); + + int *aapInt[10][20]; + secure_random_fill(aapInt, sizeof(aapInt)); + EXPECT_FALSE(mem_is_null(aapInt, sizeof(aapInt))); + mem_zero(&aapInt, sizeof(aapInt)); + EXPECT_TRUE(mem_is_null(aapInt, sizeof(aapInt))); + secure_random_fill(aapInt, sizeof(aapInt)); + EXPECT_FALSE(mem_is_null(aapInt, sizeof(aapInt))); + mem_zero(&aapInt[0], sizeof(aapInt)); + EXPECT_TRUE(mem_is_null(aapInt, sizeof(aapInt))); + + secure_random_fill(aapInt, sizeof(aapInt)); + EXPECT_FALSE(mem_is_null(aapInt, sizeof(aapInt))); + mem_zero(aapInt, sizeof(aapInt)); + EXPECT_TRUE(mem_is_null(aapInt, sizeof(aapInt))); + secure_random_fill(aapInt, sizeof(aapInt)); + EXPECT_FALSE(mem_is_null(aapInt, sizeof(aapInt))); + mem_zero(aapInt[0], sizeof(aapInt)); + EXPECT_TRUE(mem_is_null(aapInt, sizeof(aapInt))); +} + +TEST(Memory, PodTypes) +{ + NETADDR aAddr[123]; + secure_random_fill(aAddr, sizeof(aAddr)); + EXPECT_FALSE(mem_is_null(aAddr, sizeof(aAddr))); + mem_zero(&aAddr, sizeof(aAddr)); + EXPECT_TRUE(mem_is_null(aAddr, sizeof(aAddr))); + secure_random_fill(aAddr, sizeof(aAddr)); + EXPECT_FALSE(mem_is_null(aAddr, sizeof(aAddr))); + mem_zero(&aAddr[0], sizeof(aAddr)); + EXPECT_TRUE(mem_is_null(aAddr, sizeof(aAddr))); + + secure_random_fill(aAddr, sizeof(aAddr)); + EXPECT_FALSE(mem_is_null(aAddr, sizeof(aAddr))); + mem_zero(aAddr, sizeof(aAddr)); + EXPECT_TRUE(mem_is_null(aAddr, sizeof(aAddr))); + + NETADDR *apAddr[123]; + secure_random_fill(apAddr, sizeof(apAddr)); + EXPECT_FALSE(mem_is_null(apAddr, sizeof(apAddr))); + mem_zero((NETADDR **)apAddr, sizeof(apAddr)); + EXPECT_TRUE(mem_is_null(apAddr, sizeof(apAddr))); + secure_random_fill(apAddr, sizeof(apAddr)); + EXPECT_FALSE(mem_is_null(apAddr, sizeof(apAddr))); + mem_zero(&apAddr, sizeof(apAddr)); + EXPECT_TRUE(mem_is_null(apAddr, sizeof(apAddr))); + secure_random_fill(apAddr, sizeof(apAddr)); + EXPECT_FALSE(mem_is_null(apAddr, sizeof(apAddr))); + mem_zero(&apAddr[0], sizeof(apAddr)); + EXPECT_TRUE(mem_is_null(apAddr, sizeof(apAddr))); + secure_random_fill(apAddr, sizeof(apAddr)); + EXPECT_FALSE(mem_is_null(apAddr, sizeof(apAddr))); + mem_zero(apAddr, sizeof(apAddr)); + EXPECT_TRUE(mem_is_null(apAddr, sizeof(apAddr))); + + // 2D arrays + NETADDR aaAddr[10][20]; + secure_random_fill(aaAddr, sizeof(aaAddr)); + EXPECT_FALSE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + mem_zero(&aaAddr, sizeof(aaAddr)); + EXPECT_TRUE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + secure_random_fill(aaAddr, sizeof(aaAddr)); + EXPECT_FALSE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + mem_zero(&aaAddr[0], sizeof(aaAddr)); + EXPECT_TRUE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + secure_random_fill(aaAddr, sizeof(aaAddr)); + EXPECT_FALSE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + mem_zero(&aaAddr[0][0], sizeof(aaAddr)); + EXPECT_TRUE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + + secure_random_fill(aaAddr, sizeof(aaAddr)); + EXPECT_FALSE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + mem_zero(aaAddr, sizeof(aaAddr)); + EXPECT_TRUE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + secure_random_fill(aaAddr, sizeof(aaAddr)); + EXPECT_FALSE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + mem_zero(aaAddr[0], sizeof(aaAddr)); + EXPECT_TRUE(mem_is_null((NETADDR *)aaAddr, sizeof(aaAddr))); + + // 2D pointer arrays + NETADDR *aapAddr[10][20]; + secure_random_fill(aapAddr, sizeof(aapAddr)); + EXPECT_FALSE(mem_is_null(aapAddr, sizeof(aapAddr))); + mem_zero(&aapAddr, sizeof(aapAddr)); + EXPECT_TRUE(mem_is_null(aapAddr, sizeof(aapAddr))); + secure_random_fill(aapAddr, sizeof(aapAddr)); + EXPECT_FALSE(mem_is_null(aapAddr, sizeof(aapAddr))); + mem_zero(&aapAddr[0], sizeof(aapAddr)); + EXPECT_TRUE(mem_is_null(aapAddr, sizeof(aapAddr))); + secure_random_fill(aapAddr, sizeof(aapAddr)); + EXPECT_FALSE(mem_is_null(aapAddr, sizeof(aapAddr))); + mem_zero(&aapAddr[0][0], sizeof(aapAddr)); + EXPECT_TRUE(mem_is_null(aapAddr, sizeof(aapAddr))); + + secure_random_fill(aapAddr, sizeof(aapAddr)); + EXPECT_FALSE(mem_is_null(aapAddr, sizeof(aapAddr))); + mem_zero(aapAddr, sizeof(aapAddr)); + EXPECT_TRUE(mem_is_null(aapAddr, sizeof(aapAddr))); + secure_random_fill(aapAddr, sizeof(aapAddr)); + EXPECT_FALSE(mem_is_null(aapAddr, sizeof(aapAddr))); + mem_zero(aapAddr[0], sizeof(aapAddr)); + EXPECT_TRUE(mem_is_null(aapAddr, sizeof(aapAddr))); +} diff --git a/src/test/score.cpp b/src/test/score.cpp index 2e8a0f1393a..fddcefd8b3b 100644 --- a/src/test/score.cpp +++ b/src/test/score.cpp @@ -19,7 +19,7 @@ char *CSaveTeam::GetString() return nullptr; } -int CSaveTeam::FromString(char const *) +int CSaveTeam::FromString(const char *) { // Dummy implementation for testing return 1; diff --git a/src/tools/map_replace_image.cpp b/src/tools/map_replace_image.cpp index a1c755e5bf6..b67ce18aede 100644 --- a/src/tools/map_replace_image.cpp +++ b/src/tools/map_replace_image.cpp @@ -23,7 +23,7 @@ int g_NewDataID = -1; int g_NewDataSize = 0; void *g_pNewData = nullptr; -int LoadPNG(CImageInfo *pImg, const char *pFilename) +bool LoadPNG(CImageInfo *pImg, const char *pFilename) { IOHANDLE File = io_open(pFilename, IOFLAG_READ); if(File) @@ -48,23 +48,23 @@ int LoadPNG(CImageInfo *pImg, const char *pFilename) { pImg->m_pData = pImgBuffer; - if(ImageFormat == IMAGE_FORMAT_RGB) // ignore_convention + if(ImageFormat == IMAGE_FORMAT_RGB) pImg->m_Format = CImageInfo::FORMAT_RGB; - else if(ImageFormat == IMAGE_FORMAT_RGBA) // ignore_convention + else if(ImageFormat == IMAGE_FORMAT_RGBA) pImg->m_Format = CImageInfo::FORMAT_RGBA; else { free(pImgBuffer); - return 0; + return false; } } } else - return 0; + return false; } else - return 0; - return 1; + return false; + return true; } void *ReplaceImageItem(int Index, CMapItemImage *pImgItem, const char *pImgName, const char *pImgFile, CMapItemImage *pNewImgItem)