diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b46c5745ec..e8a6c3ef557 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3095,6 +3095,7 @@ if(TOOLS) demo_extract_chat dilate map_convert_07 + map_create_pixelart map_diff map_extract ) diff --git a/scripts/integration_test.sh b/scripts/integration_test.sh index 2928629071a..54b1d8cd89e 100755 --- a/scripts/integration_test.sh +++ b/scripts/integration_test.sh @@ -314,7 +314,7 @@ then echo "[-] Error: demo playback of client demo in client 2 was not started/finished" fi -ranks="$(sqlite3 ddnet-server.sqlite < <(echo "select * from record_race;"))" +ranks="$(sqlite3 -cmd '.timeout 10000' ddnet-server.sqlite < <(echo "select * from record_race;"))" rank_time="$(echo "$ranks" | awk -F '|' '{ print "player:", $2, "time:", $4, "cps:", $6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28 }')" expected_times="\ player: client2 time: 1020.98 cps: 0.02 0.1 0.2 0.26 0.32 600.36 600.42 600.46 600.5 1020.54 1020.58 1020.6 1020.64 1020.66 1020.7 1020.72 1020.76 1020.78 1020.8 1020.84 1020.86 1020.88 1020.9 diff --git a/scripts/languages/copy_fix.py b/scripts/languages/copy_fix.py index 6a624b05a4a..d80b40a059b 100755 --- a/scripts/languages/copy_fix.py +++ b/scripts/languages/copy_fix.py @@ -8,10 +8,8 @@ def copy_fix(infile, delete_unused, append_missing, delete_empty): with open(infile, encoding="utf-8") as f: content = f.readlines() trans = twlang.translations(infile) - if delete_unused or append_missing: - local = twlang.localizes() - if append_missing: - supported = [] + local = twlang.localizes() + supported = [] for tran, (start, expr, end) in trans.items(): if delete_unused and tran not in local: content[start:end] = [None]*(end-start) diff --git a/src/base/system.cpp b/src/base/system.cpp index 7820f6d5ec5..0048d3fb7d2 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -2613,7 +2613,7 @@ int net_socket_read_wait(NETSOCKET sock, int time) return 0; } -int time_timestamp() +int64_t time_timestamp() { return time(0); } diff --git a/src/base/system.h b/src/base/system.h index 5e09879cbcc..257cde71d6f 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -698,7 +698,7 @@ int64_t time_freq(); * * @return The time as a UNIX timestamp */ -int time_timestamp(); +int64_t time_timestamp(); /** * Retrieves the hours since midnight (0..23) diff --git a/src/engine/client/backend/vulkan/backend_vulkan.cpp b/src/engine/client/backend/vulkan/backend_vulkan.cpp index bd98079d6d8..3fdcd9b957d 100644 --- a/src/engine/client/backend/vulkan/backend_vulkan.cpp +++ b/src/engine/client/backend/vulkan/backend_vulkan.cpp @@ -986,8 +986,6 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase std::vector m_vWaitSemaphores; std::vector m_vSigSemaphores; - std::vector m_vMemorySemaphores; - std::vector m_vFrameFences; std::vector m_vImagesFences; @@ -1053,7 +1051,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase std::vector> m_vStreamedVertexBuffers; std::vector> m_vStreamedUniformBuffers; - uint32_t m_CurFrames = 0; + uint32_t m_CurFrameSyncObject = 0; uint32_t m_CurImageIndex = 0; uint32_t m_CanvasWidth; @@ -2275,7 +2273,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase return false; } - VkSemaphore WaitSemaphore = m_vWaitSemaphores[m_CurFrames]; + VkSemaphore WaitSemaphore = m_vWaitSemaphores[m_CurFrameSyncObject]; VkSubmitInfo SubmitInfo{}; SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; @@ -2304,13 +2302,13 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase SubmitInfo.pWaitSemaphores = aWaitSemaphores.data(); SubmitInfo.pWaitDstStageMask = aWaitStages.data(); - std::array aSignalSemaphores = {m_vSigSemaphores[m_CurFrames]}; + std::array aSignalSemaphores = {m_vSigSemaphores[m_CurFrameSyncObject]}; SubmitInfo.signalSemaphoreCount = aSignalSemaphores.size(); SubmitInfo.pSignalSemaphores = aSignalSemaphores.data(); - vkResetFences(m_VKDevice, 1, &m_vFrameFences[m_CurFrames]); + vkResetFences(m_VKDevice, 1, &m_vFrameFences[m_CurFrameSyncObject]); - VkResult QueueSubmitRes = vkQueueSubmit(m_VKGraphicsQueue, 1, &SubmitInfo, m_vFrameFences[m_CurFrames]); + VkResult QueueSubmitRes = vkQueueSubmit(m_VKGraphicsQueue, 1, &SubmitInfo, m_vFrameFences[m_CurFrameSyncObject]); if(QueueSubmitRes != VK_SUCCESS) { const char *pCritErrorMsg = CheckVulkanCriticalError(QueueSubmitRes); @@ -2321,7 +2319,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase } } - std::swap(m_vWaitSemaphores[m_CurFrames], m_vSigSemaphores[m_CurFrames]); + std::swap(m_vWaitSemaphores[m_CurFrameSyncObject], m_vSigSemaphores[m_CurFrameSyncObject]); VkPresentInfoKHR PresentInfo{}; PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -2348,7 +2346,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase } } - m_CurFrames = (m_CurFrames + 1) % m_SwapChainImageCount; + m_CurFrameSyncObject = (m_CurFrameSyncObject + 1) % m_vWaitSemaphores.size(); return true; } @@ -2364,7 +2362,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase RecreateSwapChain(); } - auto AcqResult = vkAcquireNextImageKHR(m_VKDevice, m_VKSwapChain, std::numeric_limits::max(), m_vSigSemaphores[m_CurFrames], VK_NULL_HANDLE, &m_CurImageIndex); + auto AcqResult = vkAcquireNextImageKHR(m_VKDevice, m_VKSwapChain, std::numeric_limits::max(), m_vSigSemaphores[m_CurFrameSyncObject], VK_NULL_HANDLE, &m_CurImageIndex); if(AcqResult != VK_SUCCESS) { if(AcqResult == VK_ERROR_OUT_OF_DATE_KHR || m_RecreateSwapChain) @@ -2395,13 +2393,13 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase } } } - std::swap(m_vWaitSemaphores[m_CurFrames], m_vSigSemaphores[m_CurFrames]); + std::swap(m_vWaitSemaphores[m_CurFrameSyncObject], m_vSigSemaphores[m_CurFrameSyncObject]); if(m_vImagesFences[m_CurImageIndex] != VK_NULL_HANDLE) { vkWaitForFences(m_VKDevice, 1, &m_vImagesFences[m_CurImageIndex], VK_TRUE, std::numeric_limits::max()); } - m_vImagesFences[m_CurImageIndex] = m_vFrameFences[m_CurFrames]; + m_vImagesFences[m_CurImageIndex] = m_vFrameFences[m_CurFrameSyncObject]; // next frame m_CurFrame++; @@ -5333,12 +5331,12 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase [[nodiscard]] bool CreateSyncObjects() { - m_vWaitSemaphores.resize(m_SwapChainImageCount); - m_vSigSemaphores.resize(m_SwapChainImageCount); - - m_vMemorySemaphores.resize(m_SwapChainImageCount); + // Create one more sync object than there are frames in flight + auto SyncObjectCount = m_SwapChainImageCount + 1; + m_vWaitSemaphores.resize(SyncObjectCount); + m_vSigSemaphores.resize(SyncObjectCount); - m_vFrameFences.resize(m_SwapChainImageCount); + m_vFrameFences.resize(SyncObjectCount); m_vImagesFences.resize(m_SwapChainImageCount, VK_NULL_HANDLE); VkSemaphoreCreateInfo CreateSemaphoreInfo{}; @@ -5348,11 +5346,10 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase FenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; FenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for(size_t i = 0; i < m_SwapChainImageCount; i++) + for(size_t i = 0; i < SyncObjectCount; i++) { if(vkCreateSemaphore(m_VKDevice, &CreateSemaphoreInfo, nullptr, &m_vWaitSemaphores[i]) != VK_SUCCESS || vkCreateSemaphore(m_VKDevice, &CreateSemaphoreInfo, nullptr, &m_vSigSemaphores[i]) != VK_SUCCESS || - vkCreateSemaphore(m_VKDevice, &CreateSemaphoreInfo, nullptr, &m_vMemorySemaphores[i]) != VK_SUCCESS || vkCreateFence(m_VKDevice, &FenceInfo, nullptr, &m_vFrameFences[i]) != VK_SUCCESS) { SetError(EGfxErrorType::GFX_ERROR_TYPE_INIT, "Creating swap chain sync objects(fences, semaphores) failed."); @@ -5365,21 +5362,20 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase void DestroySyncObjects() { - for(size_t i = 0; i < m_SwapChainImageCount; i++) + for(size_t i = 0; i < m_vWaitSemaphores.size(); i++) { vkDestroySemaphore(m_VKDevice, m_vWaitSemaphores[i], nullptr); vkDestroySemaphore(m_VKDevice, m_vSigSemaphores[i], nullptr); - vkDestroySemaphore(m_VKDevice, m_vMemorySemaphores[i], nullptr); vkDestroyFence(m_VKDevice, m_vFrameFences[i], nullptr); } m_vWaitSemaphores.clear(); m_vSigSemaphores.clear(); - m_vMemorySemaphores.clear(); - m_vFrameFences.clear(); m_vImagesFences.clear(); + + m_CurFrameSyncObject = 0; } void DestroyBufferOfFrame(size_t ImageIndex, SFrameBuffers &Buffer) @@ -5433,7 +5429,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase } template - void CleanupVulkan() + void CleanupVulkan(size_t SwapchainCount) { if(IsLastCleanup) { @@ -5471,7 +5467,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase m_vStreamedVertexBuffers.clear(); m_vStreamedUniformBuffers.clear(); - for(size_t i = 0; i < m_SwapChainImageCount; ++i) + for(size_t i = 0; i < SwapchainCount; ++i) { ClearFrameData(i); } @@ -5480,11 +5476,11 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase m_vvFrameDelayedTextureCleanup.clear(); m_vvFrameDelayedTextTexturesCleanup.clear(); - m_StagingBufferCache.DestroyFrameData(m_SwapChainImageCount); - m_StagingBufferCacheImage.DestroyFrameData(m_SwapChainImageCount); - m_VertexBufferCache.DestroyFrameData(m_SwapChainImageCount); + m_StagingBufferCache.DestroyFrameData(SwapchainCount); + m_StagingBufferCacheImage.DestroyFrameData(SwapchainCount); + m_VertexBufferCache.DestroyFrameData(SwapchainCount); for(auto &ImageBufferCache : m_ImageBufferCaches) - ImageBufferCache.second.DestroyFrameData(m_SwapChainImageCount); + ImageBufferCache.second.DestroyFrameData(SwapchainCount); if(IsLastCleanup) { @@ -5562,7 +5558,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase if(OldSwapChainImageCount != m_SwapChainImageCount) { - CleanupVulkan(); + CleanupVulkan(OldSwapChainImageCount); InitVulkan(); } @@ -6116,20 +6112,20 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase template int InitVulkan() { - if(!CreateDescriptorSetLayouts()) - return -1; + if(IsFirstInitialization) + { + if(!CreateDescriptorSetLayouts()) + return -1; - if(!CreateTextDescriptorSetLayout()) - return -1; + if(!CreateTextDescriptorSetLayout()) + return -1; - if(!CreateSpriteMultiUniformDescriptorSetLayout()) - return -1; + if(!CreateSpriteMultiUniformDescriptorSetLayout()) + return -1; - if(!CreateQuadUniformDescriptorSetLayout()) - return -1; + if(!CreateQuadUniformDescriptorSetLayout()) + return -1; - if(IsFirstInitialization) - { VkSwapchainKHR OldSwapChain = VK_NULL_HANDLE; if(InitVulkanSwapChain(OldSwapChain) != 0) return -1; @@ -6626,7 +6622,7 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase DestroyIndexBuffer(m_IndexBuffer, m_IndexBufferMemory); DestroyIndexBuffer(m_RenderIndexBuffer, m_RenderIndexBufferMemory); - CleanupVulkan(); + CleanupVulkan(m_SwapChainImageCount); return true; } diff --git a/src/engine/graphics.h b/src/engine/graphics.h index cfd4d8e2c6c..14017affd83 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -122,13 +122,6 @@ class CImageInfo { return m_Width * m_Height * PixelSize(m_Format); } - - static EImageFormat ImageFormatFromInt(int Format) - { - if(Format < (int)FORMAT_RGB || Format > (int)FORMAT_SINGLE_COMPONENT) - return FORMAT_ERROR; - return (EImageFormat)Format; - } }; /* diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 35626fa8837..e0c3da5bea0 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -62,6 +62,7 @@ MACRO_CONFIG_INT(ClShowNotifications, cl_shownotifications, 1, 0, 1, CFGFLAG_CLI MACRO_CONFIG_INT(ClShowEmotes, cl_showemotes, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show tee emotes") MACRO_CONFIG_INT(ClShowChat, cl_showchat, 1, 0, 2, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show chat (2 to always show large chat area)") MACRO_CONFIG_INT(ClShowChatFriends, cl_show_chat_friends, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show only chat messages from friends") +MACRO_CONFIG_INT(ClShowChatTeamMembersOnly, cl_show_chat_team_members_only, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show only chat messages from team members") MACRO_CONFIG_INT(ClShowChatSystem, cl_show_chat_system, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show chat messages from the server") MACRO_CONFIG_INT(ClShowKillMessages, cl_showkillmessages, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show kill messages") MACRO_CONFIG_INT(ClShowFinishMessages, cl_show_finish_messages, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show finish messages") diff --git a/src/engine/shared/netban.cpp b/src/engine/shared/netban.cpp index fa818abd147..71b9f589b03 100644 --- a/src/engine/shared/netban.cpp +++ b/src/engine/shared/netban.cpp @@ -217,7 +217,7 @@ int CNetBan::Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, c return -1; } - int Stamp = Seconds > 0 ? time_timestamp() + Seconds : CBanInfo::EXPIRES_NEVER; + int64_t Stamp = Seconds > 0 ? time_timestamp() + Seconds : static_cast(CBanInfo::EXPIRES_NEVER); // set up info CBanInfo Info = {0}; @@ -290,7 +290,7 @@ void CNetBan::Init(IConsole *pConsole, IStorage *pStorage) void CNetBan::Update() { - int Now = time_timestamp(); + int64_t Now = time_timestamp(); // remove expired bans char aBuf[256], aNetStr[256]; @@ -522,7 +522,7 @@ void CNetBan::ConBansSave(IConsole::IResult *pResult, void *pUser) return; } - int Now = time_timestamp(); + int64_t Now = time_timestamp(); char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE]; for(CBanAddr *pBan = pThis->m_BanAddrPool.First(); pBan; pBan = pBan->m_pNext) { diff --git a/src/engine/shared/netban.h b/src/engine/shared/netban.h index ff4ecb59d7f..1b1157daa05 100644 --- a/src/engine/shared/netban.h +++ b/src/engine/shared/netban.h @@ -79,7 +79,7 @@ class CNetBan EXPIRES_NEVER = -1, REASON_LENGTH = 64, }; - int m_Expires; + int64_t m_Expires; char m_aReason[REASON_LENGTH]; }; diff --git a/src/game/client/components/camera.cpp b/src/game/client/components/camera.cpp index 4837be0ba3e..20f2ffc8c0d 100644 --- a/src/game/client/components/camera.cpp +++ b/src/game/client/components/camera.cpp @@ -19,7 +19,7 @@ CCamera::CCamera() m_ZoomSet = false; m_Zoom = 1.0f; m_Zooming = false; - m_ForceFreeviewPos = vec2(-1, -1); + m_ForceFreeview = false; m_GotoSwitchOffset = 0; m_GotoTeleOffset = 0; m_GotoSwitchLastPos = ivec2(-1, -1); @@ -177,11 +177,14 @@ void CCamera::OnRender() m_Center = m_pClient->m_LocalCharacterPos + s_aCurrentCameraOffset[g_Config.m_ClDummy]; } - if(m_ForceFreeviewPos != vec2(-1, -1) && m_CamType == CAMTYPE_SPEC) + if(m_ForceFreeview && m_CamType == CAMTYPE_SPEC) { m_Center = m_pClient->m_Controls.m_aMousePos[g_Config.m_ClDummy] = m_ForceFreeviewPos; - m_ForceFreeviewPos = vec2(-1, -1); + m_ForceFreeview = false; } + else + m_ForceFreeviewPos = m_Center; + m_PrevCenter = m_Center; } @@ -191,6 +194,7 @@ void CCamera::OnConsoleInit() Console()->Register("zoom-", "", CFGFLAG_CLIENT, ConZoomMinus, this, "Zoom decrease"); Console()->Register("zoom", "?i", CFGFLAG_CLIENT, ConZoom, this, "Change zoom"); Console()->Register("set_view", "i[x]i[y]", CFGFLAG_CLIENT, ConSetView, this, "Set camera position to x and y in the map"); + Console()->Register("set_view_relative", "i[x]i[y]", CFGFLAG_CLIENT, ConSetViewRelative, this, "Set camera position relative to current view in the map"); Console()->Register("goto_switch", "i[number]?i[offset]", CFGFLAG_CLIENT, ConGotoSwitch, this, "View switch found (at offset) with given number"); Console()->Register("goto_tele", "i[number]?i[offset]", CFGFLAG_CLIENT, ConGotoTele, this, "View tele found (at offset) with given number"); } @@ -238,6 +242,12 @@ void CCamera::ConSetView(IConsole::IResult *pResult, void *pUserData) // wait until free view camera type to update the position pSelf->SetView(ivec2(pResult->GetInteger(0), pResult->GetInteger(1))); } +void CCamera::ConSetViewRelative(IConsole::IResult *pResult, void *pUserData) +{ + CCamera *pSelf = (CCamera *)pUserData; + // wait until free view camera type to update the position + pSelf->SetView(ivec2(pResult->GetInteger(0), pResult->GetInteger(1)), true); +} void CCamera::ConGotoSwitch(IConsole::IResult *pResult, void *pUserData) { CCamera *pSelf = (CCamera *)pUserData; @@ -249,11 +259,16 @@ void CCamera::ConGotoTele(IConsole::IResult *pResult, void *pUserData) pSelf->GotoTele(pResult->GetInteger(0), pResult->NumArguments() > 1 ? pResult->GetInteger(1) : -1); } -void CCamera::SetView(ivec2 Pos) +void CCamera::SetView(ivec2 Pos, bool Relative) { + vec2 RealPos = vec2(Pos.x * 32.0, Pos.y * 32.0); + vec2 UntestedViewPos = Relative ? m_ForceFreeviewPos + RealPos : RealPos; + + m_ForceFreeview = true; + m_ForceFreeviewPos = vec2( - clamp(Pos.x * 32.0f, 200.0f, Collision()->GetWidth() * 32 - 200.0f), - clamp(Pos.y * 32.0f, 200.0f, Collision()->GetWidth() * 32 - 200.0f)); + clamp(UntestedViewPos.x, 200.0f, Collision()->GetWidth() * 32 - 200.0f), + clamp(UntestedViewPos.y, 200.0f, Collision()->GetWidth() * 32 - 200.0f)); } void CCamera::GotoSwitch(int Number, int Offset) diff --git a/src/game/client/components/camera.h b/src/game/client/components/camera.h index ae8798d8632..c2e325eb7cb 100644 --- a/src/game/client/components/camera.h +++ b/src/game/client/components/camera.h @@ -55,7 +55,7 @@ class CCamera : public CComponent virtual void OnReset() override; void SetZoom(float Target, int Smoothness); - void SetView(ivec2 Pos); + void SetView(ivec2 Pos, bool Relative = false); void GotoSwitch(int Number, int Offset = -1); void GotoTele(int Number, int Offset = -1); @@ -64,9 +64,11 @@ class CCamera : public CComponent static void ConZoomMinus(IConsole::IResult *pResult, void *pUserData); static void ConZoom(IConsole::IResult *pResult, void *pUserData); static void ConSetView(IConsole::IResult *pResult, void *pUserData); + static void ConSetViewRelative(IConsole::IResult *pResult, void *pUserData); static void ConGotoSwitch(IConsole::IResult *pResult, void *pUserData); static void ConGotoTele(IConsole::IResult *pResult, void *pUserData); + bool m_ForceFreeview; vec2 m_ForceFreeviewPos; int m_GotoSwitchOffset; int m_GotoTeleOffset; diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp index e0f1654e202..43661d10bf7 100644 --- a/src/game/client/components/chat.cpp +++ b/src/game/client/components/chat.cpp @@ -630,6 +630,7 @@ void CChat::AddLine(int ClientId, int Team, const char *pLine) (ClientId >= 0 && (m_pClient->m_aClients[ClientId].m_aName[0] == '\0' || // unknown client m_pClient->m_aClients[ClientId].m_ChatIgnore || (m_pClient->m_Snap.m_LocalClientId != ClientId && g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[ClientId].m_Friend) || + (m_pClient->m_Snap.m_LocalClientId != ClientId && g_Config.m_ClShowChatTeamMembersOnly && m_pClient->IsOtherTeam(ClientId) && m_pClient->m_Teams.Team(m_pClient->m_Snap.m_LocalClientId) != TEAM_FLOCK) || (m_pClient->m_Snap.m_LocalClientId != ClientId && m_pClient->m_aClients[ClientId].m_Foe)))) return; @@ -1360,8 +1361,9 @@ void CChat::SendChatQueued(const char *pLine) if(AddEntry) { - CHistoryEntry *pEntry = m_History.Allocate(sizeof(CHistoryEntry) + str_length(pLine) - 1); + const int Length = str_length(pLine); + CHistoryEntry *pEntry = m_History.Allocate(sizeof(CHistoryEntry) + Length); pEntry->m_Team = m_Mode == MODE_ALL ? 0 : 1; - mem_copy(pEntry->m_aText, pLine, str_length(pLine)); + str_copy(pEntry->m_aText, pLine, Length + 1); } } diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 8c109bdbd44..fc83cdcf31e 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -468,72 +468,44 @@ int CMenus::DoButton_CheckBox_Number(const void *pId, const char *pText, int Che int CMenus::DoKeyReader(const void *pId, const CUIRect *pRect, int Key, int ModifierCombination, int *pNewModifierCombination) { - // process - static const void *s_pGrabbedId = nullptr; - static bool s_MouseReleased = true; - static int s_ButtonUsed = 0; - const bool Inside = Ui()->MouseHovered(pRect); int NewKey = Key; *pNewModifierCombination = ModifierCombination; - if(!Ui()->MouseButton(0) && !Ui()->MouseButton(1) && s_pGrabbedId == pId) - s_MouseReleased = true; - - if(Ui()->CheckActiveItem(pId)) + const int ButtonResult = Ui()->DoButtonLogic(pId, 0, pRect); + if(ButtonResult == 1) { - if(m_Binder.m_GotKey) - { - // abort with escape key - if(m_Binder.m_Key.m_Key != KEY_ESCAPE) - { - NewKey = m_Binder.m_Key.m_Key; - *pNewModifierCombination = m_Binder.m_ModifierCombination; - } - m_Binder.m_GotKey = false; - Ui()->SetActiveItem(nullptr); - s_MouseReleased = false; - s_pGrabbedId = pId; - } - - if(s_ButtonUsed == 1 && !Ui()->MouseButton(1)) - { - if(Inside) - NewKey = 0; - Ui()->SetActiveItem(nullptr); - } + m_Binder.m_pKeyReaderId = pId; + m_Binder.m_TakeKey = true; + m_Binder.m_GotKey = false; } - else if(Ui()->HotItem() == pId) + else if(ButtonResult == 2) { - if(s_MouseReleased) - { - if(Ui()->MouseButton(0)) - { - m_Binder.m_TakeKey = true; - m_Binder.m_GotKey = false; - Ui()->SetActiveItem(pId); - s_ButtonUsed = 0; - } + NewKey = 0; + *pNewModifierCombination = CBinds::MODIFIER_NONE; + } - if(Ui()->MouseButton(1)) - { - Ui()->SetActiveItem(pId); - s_ButtonUsed = 1; - } + if(m_Binder.m_pKeyReaderId == pId && m_Binder.m_GotKey) + { + // abort with escape key + if(m_Binder.m_Key.m_Key != KEY_ESCAPE) + { + NewKey = m_Binder.m_Key.m_Key; + *pNewModifierCombination = m_Binder.m_ModifierCombination; } + m_Binder.m_pKeyReaderId = nullptr; + m_Binder.m_GotKey = false; + Ui()->SetActiveItem(nullptr); } - if(Inside) - Ui()->SetHotItem(pId); - char aBuf[64]; - if(Ui()->CheckActiveItem(pId) && s_ButtonUsed == 0) + if(m_Binder.m_pKeyReaderId == pId && m_Binder.m_TakeKey) str_copy(aBuf, Localize("Press a key…")); else if(NewKey == 0) aBuf[0] = '\0'; else str_format(aBuf, sizeof(aBuf), "%s%s", CBinds::GetKeyBindModifiersName(*pNewModifierCombination), Input()->KeyName(NewKey)); - const ColorRGBA Color = Ui()->CheckActiveItem(pId) && m_Binder.m_TakeKey ? ColorRGBA(0.0f, 1.0f, 0.0f, 0.4f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f * Ui()->ButtonColorMul(pId)); + const ColorRGBA Color = m_Binder.m_pKeyReaderId == pId && m_Binder.m_TakeKey ? ColorRGBA(0.0f, 1.0f, 0.0f, 0.4f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f * Ui()->ButtonColorMul(pId)); pRect->Draw(Color, IGraphics::CORNER_ALL, 5.0f); CUIRect Temp; pRect->HMargin(1.0f, &Temp); diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index c6ac773efe6..f07231d7326 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -36,6 +36,7 @@ struct CServerProcess class CMenusKeyBinder : public CComponent { public: + const void *m_pKeyReaderId; bool m_TakeKey; bool m_GotKey; IInput::CEvent m_Key; diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 6d3ef8e618a..fb096d15e9f 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -487,17 +487,18 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) { Ui()->SetActiveItem(pId); } - else - { - 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 / Client()->GameTickSpeed() * 100, TIME_HOURS, s_aHoveredTime, sizeof(s_aHoveredTime)); - GameClient()->m_Tooltips.DoToolTip(pId, &SeekBar, s_aHoveredTime); - } } - if(Inside) + if(Inside && !Ui()->MouseButton(0)) Ui()->SetHotItem(pId); + + if(Ui()->HotItem() == pId) + { + 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 / Client()->GameTickSpeed() * 100, TIME_HOURS, s_aHoveredTime, sizeof(s_aHoveredTime)); + GameClient()->m_Tooltips.DoToolTip(pId, &SeekBar, s_aHoveredTime); + } } bool IncreaseDemoSpeed = false, DecreaseDemoSpeed = false; diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index acc036b8cf6..076ab0cb11b 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -45,9 +45,10 @@ CMenusKeyBinder CMenus::m_Binder; CMenusKeyBinder::CMenusKeyBinder() { + m_pKeyReaderId = nullptr; m_TakeKey = false; m_GotKey = false; - m_ModifierCombination = 0; + m_ModifierCombination = CBinds::MODIFIER_NONE; } bool CMenusKeyBinder::OnInput(const IInput::CEvent &Event) @@ -64,7 +65,7 @@ bool CMenusKeyBinder::OnInput(const IInput::CEvent &Event) m_ModifierCombination = CBinds::GetModifierMask(Input()); if(m_ModifierCombination == CBinds::GetModifierMaskOfKey(Event.m_Key)) { - m_ModifierCombination = 0; + m_ModifierCombination = CBinds::MODIFIER_NONE; } } return true; @@ -1066,12 +1067,9 @@ float CMenus::RenderSettingsControlsJoystick(CUIRect View) int NumOptions = 1; // expandable header if(JoystickEnabled) { - if(NumJoysticks == 0) - NumOptions++; // message - else + NumOptions++; // message or joystick name/selection + if(NumJoysticks > 0) { - if(NumJoysticks > 1) - NumOptions++; // joystick selection NumOptions += 3; // mode, ui sens, tolerance if(!g_Config.m_InpControllerAbsolute) NumOptions++; // ingame sens @@ -2615,6 +2613,7 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView) DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClChatTeamColors, Localize("Show names in chat in team colors"), &g_Config.m_ClChatTeamColors, &LeftView, LineSize); DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowChatFriends, Localize("Show only chat messages from friends"), &g_Config.m_ClShowChatFriends, &LeftView, LineSize); + DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowChatTeamMembersOnly, Localize("Show only chat messages from team members"), &g_Config.m_ClShowChatTeamMembersOnly, &LeftView, LineSize); if(DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClChatOld, Localize("Use old chat style"), &g_Config.m_ClChatOld, &LeftView, LineSize)) GameClient()->m_Chat.RebuildChat(); @@ -2892,13 +2891,15 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView) if(!g_Config.m_ClShowChatFriends) { - TempY += RenderMessageBackground(PREVIEW_HIGHLIGHT); + if(!g_Config.m_ClShowChatTeamMembersOnly) + TempY += RenderMessageBackground(PREVIEW_HIGHLIGHT); TempY += RenderMessageBackground(PREVIEW_TEAM); } - TempY += RenderMessageBackground(PREVIEW_FRIEND); + if(!g_Config.m_ClShowChatTeamMembersOnly) + TempY += RenderMessageBackground(PREVIEW_FRIEND); - if(!g_Config.m_ClShowChatFriends) + if(!g_Config.m_ClShowChatFriends && !g_Config.m_ClShowChatTeamMembersOnly) { TempY += RenderMessageBackground(PREVIEW_SPAMMER); } @@ -2917,9 +2918,10 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView) if(!g_Config.m_ClShowChatFriends) { // Highlighted - if(!g_Config.m_ClChatOld) + if(!g_Config.m_ClChatOld && !g_Config.m_ClShowChatTeamMembersOnly) RenderTools()->RenderTee(pIdleState, &s_vLines[PREVIEW_HIGHLIGHT].m_RenderInfo, EMOTE_NORMAL, vec2(1, 0.1f), vec2(X + RealTeeSizeHalved, Y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset)); - Y += RenderPreview(PREVIEW_HIGHLIGHT, X, Y).y; + if(!g_Config.m_ClShowChatTeamMembersOnly) + Y += RenderPreview(PREVIEW_HIGHLIGHT, X, Y).y; // Team if(!g_Config.m_ClChatOld) @@ -2928,12 +2930,13 @@ void CMenus::RenderSettingsAppearance(CUIRect MainView) } // Friend - if(!g_Config.m_ClChatOld) + if(!g_Config.m_ClChatOld && !g_Config.m_ClShowChatTeamMembersOnly) RenderTools()->RenderTee(pIdleState, &s_vLines[PREVIEW_FRIEND].m_RenderInfo, EMOTE_NORMAL, vec2(1, 0.1f), vec2(X + RealTeeSizeHalved, Y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset)); - Y += RenderPreview(PREVIEW_FRIEND, X, Y).y; + if(!g_Config.m_ClShowChatTeamMembersOnly) + Y += RenderPreview(PREVIEW_FRIEND, X, Y).y; // Normal - if(!g_Config.m_ClShowChatFriends) + if(!g_Config.m_ClShowChatFriends && !g_Config.m_ClShowChatTeamMembersOnly) { if(!g_Config.m_ClChatOld) RenderTools()->RenderTee(pIdleState, &s_vLines[PREVIEW_SPAMMER].m_RenderInfo, EMOTE_NORMAL, vec2(1, 0.1f), vec2(X + RealTeeSizeHalved, Y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset)); diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp index b435f8eefbe..8b9458c3f15 100644 --- a/src/game/client/ui.cpp +++ b/src/game/client/ui.cpp @@ -798,7 +798,7 @@ bool CUi::DoEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize } } - if(Inside) + if(Inside && !MouseButton(0)) SetHotItem(pLineInput); if(Enabled() && Active && !JustGotActive) @@ -1013,9 +1013,6 @@ SEditResult CUi::DoValueSelectorWithState(const void *pId, const CUIRec static const void *s_pEditing = nullptr; EEditState State = EEditState::NONE; - if(Inside) - SetHotItem(pId); - const int Base = Props.m_IsHex ? 16 : 10; if(MouseButtonReleased(1) && HotItem() == pId) @@ -1113,6 +1110,9 @@ SEditResult CUi::DoValueSelectorWithState(const void *pId, const CUIRec DoLabel(pRect, aBuf, 10.0f, TEXTALIGN_MC); } + if(Inside && !MouseButton(0)) + SetHotItem(pId); + if(!m_ValueSelectorTextMode) s_NumberInput.Clear(); @@ -1182,7 +1182,7 @@ float CUi::DoScrollbarV(const void *pId, const CUIRect *pRect, float Current) Grabbed = true; } - if(InsideHandle) + if(InsideHandle && !MouseButton(0)) { SetHotItem(pId); } @@ -1253,7 +1253,7 @@ float CUi::DoScrollbarH(const void *pId, const CUIRect *pRect, float Current, co Grabbed = true; } - if(InsideHandle) + if(InsideHandle && !MouseButton(0)) { SetHotItem(pId); } diff --git a/src/game/client/ui_scrollregion.cpp b/src/game/client/ui_scrollregion.cpp index 1f549a7cf3a..a4d8abe6fb5 100644 --- a/src/game/client/ui_scrollregion.cpp +++ b/src/game/client/ui_scrollregion.cpp @@ -160,7 +160,8 @@ void CScrollRegion::End() } else if(InsideSlider) { - Ui()->SetHotItem(pId); + if(!Ui()->MouseButton(0)) + Ui()->SetHotItem(pId); if(!Ui()->CheckActiveItem(pId) && Ui()->MouseButtonClicked(0)) { @@ -179,7 +180,8 @@ void CScrollRegion::End() m_AnimTargetScrollY = m_ScrollY; m_AnimTime = 0.0f; } - else if(Ui()->CheckActiveItem(pId) && !Ui()->MouseButton(0)) + + if(Ui()->CheckActiveItem(pId) && !Ui()->MouseButton(0)) { Ui()->SetActiveItem(nullptr); } diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 0a20304c22e..dd6ba9777f1 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -387,7 +387,7 @@ SEditResult CEditor::UiDoValueSelector(void *pId, CUIRect *pRect, const cha str_copy(m_aTooltip, pToolTip); } - if(Inside) + if(Inside && !Ui()->MouseButton(0)) Ui()->SetHotItem(pId); // render @@ -996,7 +996,7 @@ void CEditor::DoAudioPreview(CUIRect View, const void *pPlayPauseButtonId, const Ui()->SetActiveItem(pSeekBarId); } - if(Inside) + if(Inside && !Ui()->MouseButton(0)) Ui()->SetHotItem(pSeekBarId); } } diff --git a/src/game/server/instagib/round_stats.cpp b/src/game/server/instagib/round_stats.cpp index 8b0268d241f..a817f2a6108 100644 --- a/src/game/server/instagib/round_stats.cpp +++ b/src/game/server/instagib/round_stats.cpp @@ -21,6 +21,18 @@ void IGameController::OnEndMatchInsta() dbg_msg("ddnet-insta", "building stats ..."); GetRoundEndStatsStr(aStats, sizeof(aStats)); PublishRoundEndStatsStr(aStats); + + for(CInstaPlayerStats &Stats : m_aInstaPlayerStats) + Stats.Reset(); +} + +static float CalcKillDeathRatio(int Kills, int Deaths) +{ + if(!Kills) + return 0; + if(!Deaths) + return (float)Kills; + return (float)Kills / (float)Deaths; } void IGameController::PsvRowPlayer(const CPlayer *pPlayer, char *pBuf, size_t Size) @@ -36,7 +48,7 @@ void IGameController::PsvRowPlayer(const CPlayer *pPlayer, char *pBuf, size_t Si pPlayer->m_Score.value_or(0), pStats->m_Kills, pStats->m_Deaths, - (float)pStats->m_Kills / ((float)pStats->m_Kills + (float)pStats->m_Deaths)); + CalcKillDeathRatio(pStats->m_Kills, pStats->m_Deaths)); str_append(pBuf, aBuf, Size); } diff --git a/src/tools/map_create_pixelart.cpp b/src/tools/map_create_pixelart.cpp index 9b9e258d342..b2486b17651 100644 --- a/src/tools/map_create_pixelart.cpp +++ b/src/tools/map_create_pixelart.cpp @@ -6,12 +6,12 @@ #include #include -bool CreatePixelArt(const char[3][64], const int[2], const int[2], int[2], const bool[2]); +bool CreatePixelArt(const char[3][IO_MAX_PATH_LENGTH], const int[2], const int[2], int[2], const bool[2]); void InsertCurrentQuads(CDataFileReader &, CMapItemLayerQuads *, CQuad *); int InsertPixelArtQuads(CQuad *, int &, const CImageInfo &, const int[2], const int[2], const bool[2]); bool LoadPng(CImageInfo *, const char *); -bool OpenMaps(const char[2][64], CDataFileReader &, CDataFileWriter &); +bool OpenMaps(const char[2][IO_MAX_PATH_LENGTH], CDataFileReader &, CDataFileWriter &); void SaveOutputMap(CDataFileReader &, CDataFileWriter &, CMapItemLayerQuads *, int, CQuad *, int); CMapItemLayerQuads *GetQuadLayer(CDataFileReader &, const int[2], int *); @@ -31,7 +31,7 @@ int main(int argc, const char **argv) CCmdlineFix CmdlineFix(&argc, &argv); log_set_global_logger_default(); - if(argc < 9 || argc > 12) + if(argc < 10 || argc > 12) { dbg_msg("map_create_pixelart", "Invalid arguments"); dbg_msg("map_create_pixelart", "Usage: %s [optimize=0|1] [centralize=0|1]", argv[0]); @@ -45,26 +45,32 @@ int main(int argc, const char **argv) return -1; } - char aFilenames[3][64]; + char aFilenames[3][IO_MAX_PATH_LENGTH]; str_copy(aFilenames[0], argv[3]); //input_map str_copy(aFilenames[1], argv[9]); //output_map str_copy(aFilenames[2], argv[1]); //image_file + if(str_comp_filenames(aFilenames[0], aFilenames[1]) == 0) + { + dbg_msg("map_create_pixelart", "Invalid usage: you can not use the same map as input and output"); + return -1; + } + int aLayerId[2] = {str_toint(argv[4]), str_toint(argv[5])}; //layergroup_id, layer_id int aStartingPos[2] = {str_toint(argv[6]) * 32, str_toint(argv[7]) * 32}; //pos_x, pos_y int aPixelSizes[2] = {str_toint(argv[2]), str_toint(argv[8])}; //quad_pixelsize, img_pixelsize bool aArtOptions[3]; - aArtOptions[0] = argc >= 10 ? str_toint(argv[10]) : true; //optimize - aArtOptions[1] = argc >= 11 ? str_toint(argv[11]) : false; //centralize + aArtOptions[0] = argc > 10 ? str_toint(argv[10]) : true; //optimize + aArtOptions[1] = argc > 11 ? str_toint(argv[11]) : false; //centralize dbg_msg("map_create_pixelart", "image_file='%s'; image_pixelsize='%dpx'; input_map='%s'; layergroup_id='#%d'; layer_id='#%d'; pos_x='#%dpx'; pos_y='%dpx'; quad_pixelsize='%dpx'; output_map='%s'; optimize='%d'; centralize='%d'", - aFilenames[2], aPixelSizes[0], aFilenames[1], aLayerId[0], aLayerId[1], aStartingPos[0], aStartingPos[1], aPixelSizes[1], aFilenames[2], aArtOptions[0], aArtOptions[1]); + aFilenames[2], aPixelSizes[0], aFilenames[0], aLayerId[0], aLayerId[1], aStartingPos[0], aStartingPos[1], aPixelSizes[1], aFilenames[1], aArtOptions[0], aArtOptions[1]); return !CreatePixelArt(aFilenames, aLayerId, aStartingPos, aPixelSizes, aArtOptions); } -bool CreatePixelArt(const char aFilenames[3][64], const int aLayerId[2], const int aStartingPos[2], int aPixelSizes[2], const bool aArtOptions[2]) +bool CreatePixelArt(const char aFilenames[3][IO_MAX_PATH_LENGTH], const int aLayerId[2], const int aStartingPos[2], int aPixelSizes[2], const bool aArtOptions[2]) { CImageInfo Img; if(!LoadPng(&Img, aFilenames[2])) @@ -88,7 +94,7 @@ bool CreatePixelArt(const char aFilenames[3][64], const int aLayerId[2], const i InsertCurrentQuads(InputMap, pQuadLayer, pQuads); int QuadsCounter = InsertPixelArtQuads(pQuads, pQuadLayer->m_NumQuads, Img, aStartingPos, aPixelSizes, aArtOptions); - SaveOutputMap(InputMap, OutputMap, pQuadLayer, ItemNumber, pQuads, ((int)sizeof(CQuad)) * (pQuadLayer->m_NumQuads + 1)); + SaveOutputMap(InputMap, OutputMap, pQuadLayer, ItemNumber, pQuads, (int)sizeof(CQuad) * pQuadLayer->m_NumQuads); delete[] pQuads; dbg_msg("map_create_pixelart", "INFO: successfully added %d new pixelart quads.", QuadsCounter); @@ -357,7 +363,7 @@ bool LoadPng(CImageInfo *pImg, const char *pFilename) return true; } -bool OpenMaps(const char pMapNames[2][64], CDataFileReader &InputMap, CDataFileWriter &OutputMap) +bool OpenMaps(const char pMapNames[2][IO_MAX_PATH_LENGTH], CDataFileReader &InputMap, CDataFileWriter &OutputMap) { IStorage *pStorage = CreateLocalStorage();