diff --git a/Client/core/CClientVariables.cpp b/Client/core/CClientVariables.cpp index 8019c2687b..0397dbf264 100644 --- a/Client/core/CClientVariables.cpp +++ b/Client/core/CClientVariables.cpp @@ -256,6 +256,7 @@ void CClientVariables::ValidateValues() ClampValue("mtavolume", 0.0f, 1.0f); ClampValue("voicevolume", 0.0f, 1.0f); ClampValue("mapalpha", 0, 255); + ClampValue("mapimage", 0, 1); } void CClientVariables::LoadDefaults() @@ -313,7 +314,8 @@ void CClientVariables::LoadDefaults() DEFAULT("mastervolume", 1.0f); // master volume DEFAULT("mtavolume", 1.0f); // custom sound's volume DEFAULT("voicevolume", 1.0f); // voice chat output volume - DEFAULT("mapalpha", 155); // map alpha + DEFAULT("mapalpha", 155); // player map alpha + DEFAULT("mapimage", 0); // player map image DEFAULT("browser_speed", 1); // Browser speed DEFAULT("single_download", 0); // Single connection for downloads DEFAULT("packet_tag", 0); // Tag network packets diff --git a/Client/core/CSettings.cpp b/Client/core/CSettings.cpp index 1cfe5c90eb..6792bac450 100644 --- a/Client/core/CSettings.cpp +++ b/Client/core/CSettings.cpp @@ -376,7 +376,7 @@ void CSettings::CreateGUI() m_pButtonGenerateNickIcon->SetProperty("DistributeCapturedInputs", "True"); m_pSavePasswords = reinterpret_cast(pManager->CreateCheckBox(pTabMultiplayer, _("Save server passwords"), true)); - m_pSavePasswords->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 50.0f)); + m_pSavePasswords->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 35.0f)); m_pSavePasswords->GetPosition(vecTemp, false); m_pSavePasswords->AutoSize(NULL, 20.0f); @@ -411,11 +411,13 @@ void CSettings::CreateGUI() m_pCheckBoxCustomizedSAFiles->AutoSize(NULL, 20.0f); m_pMapRenderingLabel = reinterpret_cast(pManager->CreateLabel(pTabMultiplayer, _("Map rendering options"))); - m_pMapRenderingLabel->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 29.0f)); + m_pMapRenderingLabel->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 30.0f)); m_pMapRenderingLabel->GetPosition(vecTemp, false); m_pMapRenderingLabel->SetFont("default-bold-small"); m_pMapRenderingLabel->AutoSize(); + vecTemp.fX += 5.0f; + m_pMapAlphaLabel = reinterpret_cast(pManager->CreateLabel(pTabMultiplayer, _("Opacity:"))); m_pMapAlphaLabel->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 24.0f)); m_pMapAlphaLabel->GetPosition(vecTemp, false); @@ -433,6 +435,20 @@ void CSettings::CreateGUI() m_pMapAlphaValueLabel->GetPosition(vecTemp, false); m_pMapAlphaValueLabel->AutoSize("100%"); + m_pMapAlphaLabel->GetPosition(vecTemp, false); + vecTemp.fY += 24.0f; + + m_pPlayerMapImageLabel = reinterpret_cast(pManager->CreateLabel(pTabMultiplayer, _("Image resolution:"))); + m_pPlayerMapImageLabel->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 2.0f)); + m_pPlayerMapImageLabel->AutoSize(); + + m_pPlayerMapImageCombo = reinterpret_cast(pManager->CreateComboBox(pTabMultiplayer, "")); + m_pPlayerMapImageCombo->SetPosition(CVector2D(vecTemp.fX + fIndentX + 5.0f, vecTemp.fY - 1.0f)); + m_pPlayerMapImageCombo->SetSize(CVector2D(170.f, 95.0f)); + m_pPlayerMapImageCombo->AddItem(_("1024 x 1024 (Default)")); // index 0 + m_pPlayerMapImageCombo->AddItem(_("2048 x 2048")); // index 1 + m_pPlayerMapImageCombo->SetReadOnly(true); + /** * Audio tab **/ @@ -625,16 +641,13 @@ void CSettings::CreateGUI() * Video tab **/ fIndentX = pManager->CGUI_GetMaxTextExtent("default-normal", _("Resolution:"), _("FOV:"), _("Draw Distance:"), _("Brightness:"), _("FX Quality:"), - _("Anisotropic filtering:"), _("Anti-aliasing:"), _("Aspect Ratio:"), _("Opacity:")); + _("Anisotropic filtering:"), _("Anti-aliasing:"), _("Aspect Ratio:")); - m_pVideoGeneralLabel = reinterpret_cast(pManager->CreateLabel(pTabVideo, _("General"))); - m_pVideoGeneralLabel->SetPosition(CVector2D(11, 13)); - m_pVideoGeneralLabel->GetPosition(vecTemp, false); - m_pVideoGeneralLabel->AutoSize(NULL, 3.0f); - m_pVideoGeneralLabel->SetFont("default-bold-small"); + vecTemp.fX = 11.0f; + vecTemp.fY = 13.0f; m_pVideoResolutionLabel = reinterpret_cast(pManager->CreateLabel(pTabVideo, _("Resolution:"))); - m_pVideoResolutionLabel->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 26.0f)); + m_pVideoResolutionLabel->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY)); m_pVideoResolutionLabel->GetPosition(vecTemp, false); m_pVideoResolutionLabel->AutoSize(); @@ -833,6 +846,10 @@ void CSettings::CreateGUI() m_pCheckBoxBlur->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 130.0f)); m_pCheckBoxBlur->AutoSize(NULL, 20.0f); + m_pCheckBoxCoronaReflections = reinterpret_cast(pManager->CreateCheckBox(pTabVideo, _("Corona rain reflections"), true)); + m_pCheckBoxCoronaReflections->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY + 150.0f)); + m_pCheckBoxCoronaReflections->AutoSize(nullptr, 20.0f); + float fPosY = vecTemp.fY; m_pCheckBoxMinimize = reinterpret_cast(pManager->CreateCheckBox(pTabVideo, _("Full Screen Minimize"), true)); m_pCheckBoxMinimize->SetPosition(CVector2D(vecTemp.fX + 245.0f, fPosY + 30.0f)); @@ -878,10 +895,6 @@ void CSettings::CreateGUI() m_pCheckBoxHighDetailPeds->SetPosition(CVector2D(vecTemp.fX + 245.0f, fPosY + 110.0f)); m_pCheckBoxHighDetailPeds->AutoSize(NULL, 20.0f); - m_pCheckBoxCoronaReflections = reinterpret_cast(pManager->CreateCheckBox(pTabVideo, _("Corona rain reflections"), true)); - m_pCheckBoxCoronaReflections->SetPosition(CVector2D(vecTemp.fX + 245.0f, fPosY + 130.0f)); - m_pCheckBoxCoronaReflections->AutoSize(NULL, 20.0f); - vecTemp.fY += 10; m_pTabs->GetSize(vecTemp); @@ -1010,6 +1023,7 @@ void CSettings::CreateGUI() 5.0f; vecTemp.fX += 10.0f; + // Fast clothes loading m_pFastClothesLabel = reinterpret_cast(pManager->CreateLabel(pTabAdvanced, _("Fast CJ clothes loading:"))); m_pFastClothesLabel->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY)); @@ -1238,7 +1252,7 @@ void CSettings::CreateGUI() vecTemp.fX -= fComboWidth + 15; // Description label - vecTemp.fY = 354 + 10; + vecTemp.fY += 15.0f; m_pAdvancedSettingDescriptionLabel = reinterpret_cast(pManager->CreateLabel(pTabAdvanced, "")); m_pAdvancedSettingDescriptionLabel->SetPosition(CVector2D(vecTemp.fX + 10.f, vecTemp.fY)); m_pAdvancedSettingDescriptionLabel->SetFont("default-bold-small"); @@ -1629,12 +1643,17 @@ void CSettings::UpdateVideoTab() float fPos = SharedUtil::Unlerp(g_pCore->GetMinStreamingMemory(), uiStreamingMemory, g_pCore->GetMaxStreamingMemory()); m_pStreamingMemory->SetScrollPosition(fPos); + // Player map alpha int iVar = 0; CVARS_GET("mapalpha", iVar); int iAlphaPercent = ceil(((float)Clamp(0, iVar, 255) / 255) * 100); m_pMapAlphaValueLabel->SetText(SString("%i%%", iAlphaPercent).c_str()); float sbPos = (float)iAlphaPercent / 100.0f; m_pMapAlpha->SetScrollPosition(sbPos); + + // Player map image + CVARS_GET("mapimage", iVar); + m_pPlayerMapImageCombo->SetSelectedItemByIndex(iVar); } // @@ -1851,7 +1870,9 @@ bool CSettings::OnVideoDefaultClick(CGUIElement* pElement) CVARS_SET("streaming_memory", g_pCore->GetMaxStreamingMemory()); + // Player map defaults CVARS_SET("mapalpha", 155); + CVARS_SET("mapimage", 0); // Display restart required message if required bool bIsAntiAliasingChanged = gameSettings->GetAntiAliasing() != m_pComboAntiAliasing->GetSelectedItemIndex(); @@ -3609,12 +3630,16 @@ void CSettings::SaveData() CVARS_SET("update_auto_install", iSelected); } - // Map alpha + // Player map alpha SString sText = m_pMapAlphaValueLabel->GetText(); - float fMapAlpha = ((atof(sText.substr(0, sText.length() - 1).c_str())) / 100) * 255; CVARS_SET("mapalpha", fMapAlpha); + // Player map image + int selectedComboIndex = m_pPlayerMapImageCombo->GetSelectedItemIndex(); + if (selectedComboIndex != -1) + CVARS_SET("mapimage", selectedComboIndex); + // Language CGUIListItem* pItem = m_pInterfaceLanguageSelector->GetSelectedItem(); if (pItem) diff --git a/Client/core/CSettings.h b/Client/core/CSettings.h index db6c077df4..9c288557e6 100644 --- a/Client/core/CSettings.h +++ b/Client/core/CSettings.h @@ -196,6 +196,8 @@ class CSettings CGUIComboBox* m_pFullscreenStyleCombo; CGUILabel* m_pPriorityLabel; CGUIComboBox* m_pPriorityCombo; + CGUILabel* m_pPlayerMapImageLabel; + CGUIComboBox* m_pPlayerMapImageCombo; CGUILabel* m_pFastClothesLabel; CGUIComboBox* m_pFastClothesCombo; CGUILabel* m_pAudioGeneralLabel; diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 07ac611c09..918091d482 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -848,6 +848,34 @@ void CGameSA::SetRoadSignsTextEnabled(bool isEnabled) m_isRoadSignsTextEnabled = isEnabled; } +void CGameSA::SetIgnoreFireStateEnabled(bool isEnabled) +{ + if (isEnabled == m_isIgnoreFireStateEnabled) + return; + + if (isEnabled) + { + MemSet((void*)0x6511B9, 0x90, 10); // CCarEnterExit::IsVehicleStealable + MemSet((void*)0x643A95, 0x90, 14); // CTaskComplexEnterCar::CreateFirstSubTask + MemSet((void*)0x6900B5, 0x90, 14); // CTaskComplexCopInCar::ControlSubTask + MemSet((void*)0x64F3DB, 0x90, 14); // CCarEnterExit::IsPlayerToQuitCarEnter + + MemSet((void*)0x685A7F, 0x90, 14); // CTaskSimplePlayerOnFoot::ProcessPlayerWeapon + } + else + { + // Restore original bytes + MemCpy((void*)0x6511B9, "\x88\x86\x90\x04\x00\x00\x85\xC0\x75\x3E", 10); + MemCpy((void*)0x643A95, "\x8B\x88\x90\x04\x00\x00\x85\xC9\x0F\x85\x99\x01\x00\x00", 14); + MemCpy((void*)0x6900B5, "\x8B\x81\x90\x04\x00\x00\x85\xC0\x0F\x85\x1A\x01\x00\x00", 14); + MemCpy((void*)0x64F3DB, "\x8B\x85\x90\x04\x00\x00\x85\xC0\x0F\x85\x1B\x01\x00\x00", 14); + + MemCpy((void*)0x685A7F, "\x8B\x86\x30\x07\x00\x00\x85\xC0\x0F\x85\x1D\x01\x00\x00", 14); + } + + m_isIgnoreFireStateEnabled = isEnabled; +} + bool CGameSA::PerformChecks() { std::map::iterator it; diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index cf4788d953..33731af858 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -249,6 +249,8 @@ class CGameSA : public CGame bool IsTunnelWeatherBlendEnabled() const noexcept override { return m_isTunnelWeatherBlendEnabled; } void SetTunnelWeatherBlendEnabled(bool isEnabled) override; + bool IsIgnoreFireStateEnabled() const noexcept override { return m_isIgnoreFireStateEnabled; } + void SetIgnoreFireStateEnabled(bool isEnabled) override; unsigned long GetMinuteDuration(); void SetMinuteDuration(unsigned long ulTime); @@ -378,6 +380,7 @@ class CGameSA : public CGame bool m_isRoadSignsTextEnabled{true}; bool m_isBuildingsRemoved{false}; bool m_isExtendedWaterCannonsEnabled{false}; + bool m_isIgnoreFireStateEnabled{false}; static unsigned int& ClumpOffset; diff --git a/Client/mods/deathmatch/CClient.cpp b/Client/mods/deathmatch/CClient.cpp index ec17655996..e532ef2f71 100644 --- a/Client/mods/deathmatch/CClient.cpp +++ b/Client/mods/deathmatch/CClient.cpp @@ -64,17 +64,17 @@ int CClient::ClientInitialize(const char* szArguments, CCoreInterface* pCore) g_pCore->GetCommands()->Add("enter_passenger", _("enters a car as passenger"), COMMAND_EnterPassenger, true, true); g_pCore->GetCommands()->Add("radio_next", _("next radio channel"), COMMAND_RadioNext, true, true); g_pCore->GetCommands()->Add("radio_previous", _("previous radio channel"), COMMAND_RadioPrevious, true, true); - g_pCore->GetCommands()->Add("radar", _("enables the radar view"), COMMAND_RadarMap, true, true); - g_pCore->GetCommands()->Add("radar_zoom_in", _("zooms the radar in"), COMMAND_RadarZoomIn, true, true); - g_pCore->GetCommands()->Add("radar_zoom_out", _("zooms the radar out"), COMMAND_RadarZoomOut, true, true); - g_pCore->GetCommands()->Add("radar_move_north", _("moves the radar north"), COMMAND_RadarMoveNorth, true, true); - g_pCore->GetCommands()->Add("radar_move_south", _("moves the radar south"), COMMAND_RadarMoveSouth, true, true); - g_pCore->GetCommands()->Add("radar_move_east", _("moves the radar east"), COMMAND_RadarMoveEast, true, true); - g_pCore->GetCommands()->Add("radar_move_west", _("moves the radar west"), COMMAND_RadarMoveWest, true, true); - g_pCore->GetCommands()->Add("radar_attach", _("attaches the radar"), COMMAND_RadarAttach, true, true); - g_pCore->GetCommands()->Add("radar_opacity_down", _("reduces radar opacity"), COMMAND_RadarOpacityDown, true, true); - g_pCore->GetCommands()->Add("radar_opacity_up", _("increases radar opacity"), COMMAND_RadarOpacityUp, true, true); - g_pCore->GetCommands()->Add("radar_help", _("toggles radar help text"), COMMAND_RadarHelp, true, true); + g_pCore->GetCommands()->Add("radar", _("enables the player-map view"), COMMAND_PlayerMap, true, true); + g_pCore->GetCommands()->Add("radar_zoom_in", _("zooms the player-map in"), COMMAND_PlayerMapZoomIn, true, true); + g_pCore->GetCommands()->Add("radar_zoom_out", _("zooms the player-map out"), COMMAND_PlayerMapZoomOut, true, true); + g_pCore->GetCommands()->Add("radar_move_north", _("moves the player-map north"), COMMAND_PlayerMapMoveNorth, true, true); + g_pCore->GetCommands()->Add("radar_move_south", _("moves the player-map south"), COMMAND_PlayerMapMoveSouth, true, true); + g_pCore->GetCommands()->Add("radar_move_east", _("moves the player-map east"), COMMAND_PlayerMapMoveEast, true, true); + g_pCore->GetCommands()->Add("radar_move_west", _("moves the player-map west"), COMMAND_PlayerMapMoveWest, true, true); + g_pCore->GetCommands()->Add("radar_attach", _("attaches the player-map"), COMMAND_PlayerMapAttach, true, true); + g_pCore->GetCommands()->Add("radar_opacity_down", _("reduces player-map opacity"), COMMAND_PlayerMapOpacityDown, true, true); + g_pCore->GetCommands()->Add("radar_opacity_up", _("increases player-map opacity"), COMMAND_PlayerMapOpacityUp, true, true); + g_pCore->GetCommands()->Add("radar_help", _("toggles player-map help text"), COMMAND_PlayerMapHelp, true, true); g_pCore->GetCommands()->Add("msg_target", _("sends a message to the targetted player"), COMMAND_MessageTarget, true); g_pCore->GetCommands()->Add("vehicle_next_weapon", _("changes to the next weapon whilst in a vehicle"), COMMAND_VehicleNextWeapon, true); g_pCore->GetCommands()->Add("vehicle_previous_weapon", _("changes to the previous weapon whilst in a vehicle"), COMMAND_VehiclePreviousWeapon, true); diff --git a/Client/mods/deathmatch/ClientCommands.cpp b/Client/mods/deathmatch/ClientCommands.cpp index 6ca4d73625..123ee59dcb 100644 --- a/Client/mods/deathmatch/ClientCommands.cpp +++ b/Client/mods/deathmatch/ClientCommands.cpp @@ -235,154 +235,137 @@ void COMMAND_Screenshot ( const char* szCmdLine ) } */ -void COMMAND_RadarMap(const char* szCmdLine) +void COMMAND_PlayerMap(const char* szCmdLine) { - int iCmd = (szCmdLine && szCmdLine[0]) ? atoi(szCmdLine) : -1; - bool bShow = (iCmd == 1) ? true : (iCmd == 0) ? false : !g_pClientGame->GetRadarMap()->GetRadarEnabled(); - g_pClientGame->GetRadarMap()->SetRadarEnabled(bShow); + int cmd = (szCmdLine && szCmdLine[0]) ? atoi(szCmdLine) : -1; + bool show = (cmd == 1) ? true : (cmd == 0) ? false : !g_pClientGame->GetPlayerMap()->GetPlayerMapEnabled(); + g_pClientGame->GetPlayerMap()->SetPlayerMapEnabled(show); } -void COMMAND_RadarZoomIn(const char* szCmdLine) +void COMMAND_PlayerMapZoomIn(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); - - if (pRadarMap->IsRadarShowing()) - { - pRadarMap->ZoomIn(); - } + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (playerMap->IsPlayerMapShowing()) + playerMap->ZoomIn(); } -void COMMAND_RadarZoomOut(const char* szCmdLine) +void COMMAND_PlayerMapZoomOut(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); - - if (pRadarMap->IsRadarShowing()) - { - pRadarMap->ZoomOut(); - } + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (playerMap->IsPlayerMapShowing()) + playerMap->ZoomOut(); } -void COMMAND_RadarMoveNorth(const char* szCmdLine) +void COMMAND_PlayerMapMoveNorth(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (!playerMap->IsPlayerMapShowing()) + return; - if (pRadarMap->IsRadarShowing()) + if (playerMap->IsMovingNorth()) + playerMap->SetMovingNorth(false); + else if (playerMap->IsMovingSouth()) + playerMap->SetMovingSouth(false); + else { - // Toggle on/off - if (pRadarMap->IsMovingNorth()) - pRadarMap->SetMovingNorth(false); - else if (pRadarMap->IsMovingSouth()) - pRadarMap->SetMovingSouth(false); - else - { - pRadarMap->SetMovingNorth(true); - pRadarMap->SetMovingSouth(false); - pRadarMap->SetMovingEast(false); - pRadarMap->SetMovingWest(false); - } + playerMap->SetMovingNorth(true); + playerMap->SetMovingSouth(false); + playerMap->SetMovingEast(false); + playerMap->SetMovingWest(false); } } -void COMMAND_RadarMoveSouth(const char* szCmdLine) +void COMMAND_PlayerMapMoveSouth(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (!playerMap->IsPlayerMapShowing()) + return; - if (pRadarMap->IsRadarShowing()) + if (playerMap->IsMovingSouth()) + playerMap->SetMovingSouth(false); + else if (playerMap->IsMovingNorth()) + playerMap->SetMovingNorth(false); + else { - // Toggle on/off - if (pRadarMap->IsMovingSouth()) - pRadarMap->SetMovingSouth(false); - else if (pRadarMap->IsMovingNorth()) - pRadarMap->SetMovingNorth(false); - else - { - pRadarMap->SetMovingNorth(false); - pRadarMap->SetMovingSouth(true); - pRadarMap->SetMovingEast(false); - pRadarMap->SetMovingWest(false); - } + playerMap->SetMovingNorth(false); + playerMap->SetMovingSouth(true); + playerMap->SetMovingEast(false); + playerMap->SetMovingWest(false); } } -void COMMAND_RadarMoveEast(const char* szCmdLine) +void COMMAND_PlayerMapMoveEast(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (!playerMap->IsPlayerMapShowing()) + return; - if (pRadarMap->IsRadarShowing()) + if (playerMap->IsMovingEast()) + playerMap->SetMovingEast(false); + else if (playerMap->IsMovingWest()) + playerMap->SetMovingWest(false); + else { - // Toggle on/off - if (pRadarMap->IsMovingEast()) - pRadarMap->SetMovingEast(false); - else if (pRadarMap->IsMovingWest()) - pRadarMap->SetMovingWest(false); - else - { - pRadarMap->SetMovingNorth(false); - pRadarMap->SetMovingSouth(false); - pRadarMap->SetMovingEast(true); - pRadarMap->SetMovingWest(false); - } + playerMap->SetMovingNorth(false); + playerMap->SetMovingSouth(false); + playerMap->SetMovingEast(true); + playerMap->SetMovingWest(false); } } -void COMMAND_RadarMoveWest(const char* szCmdLine) +void COMMAND_PlayerMapMoveWest(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (!playerMap->IsPlayerMapShowing()) + return; - if (pRadarMap->IsRadarShowing()) + if (playerMap->IsMovingWest()) + playerMap->SetMovingWest(false); + else if (playerMap->IsMovingEast()) + playerMap->SetMovingEast(false); + else { - // Toggle on/off - if (pRadarMap->IsMovingWest()) - pRadarMap->SetMovingWest(false); - else if (pRadarMap->IsMovingEast()) - pRadarMap->SetMovingEast(false); - else - { - pRadarMap->SetMovingNorth(false); - pRadarMap->SetMovingSouth(false); - pRadarMap->SetMovingEast(false); - pRadarMap->SetMovingWest(true); - } + playerMap->SetMovingNorth(false); + playerMap->SetMovingSouth(false); + playerMap->SetMovingEast(false); + playerMap->SetMovingWest(true); } } -void COMMAND_RadarAttach(const char* szCmdLine) +void COMMAND_PlayerMapAttach(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); - - if (pRadarMap->IsRadarShowing()) - { - pRadarMap->SetAttachedToLocalPlayer(!g_pClientGame->GetRadarMap()->IsAttachedToLocalPlayer()); - } + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (playerMap->IsPlayerMapShowing()) + playerMap->SetAttachedToLocalPlayer(!g_pClientGame->GetPlayerMap()->IsAttachedToLocalPlayer()); } -void COMMAND_RadarOpacityDown(const char* szCmdLine) +void COMMAND_PlayerMapOpacityDown(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); - if (pRadarMap->IsRadarShowing()) - { - int iAlpha; - g_pCore->GetCVars()->Get("mapalpha", iAlpha); - iAlpha = std::max(0, iAlpha - 20); - g_pCore->GetCVars()->Set("mapalpha", iAlpha); - } + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (!playerMap->IsPlayerMapShowing()) + return; + + int mapAlpha; + g_pCore->GetCVars()->Get("mapalpha", mapAlpha); + mapAlpha = std::max(0, mapAlpha - 20); + g_pCore->GetCVars()->Set("mapalpha", mapAlpha); } -void COMMAND_RadarOpacityUp(const char* szCmdLine) +void COMMAND_PlayerMapOpacityUp(const char* szCmdLine) { - CRadarMap* pRadarMap = g_pClientGame->GetRadarMap(); - if (pRadarMap->IsRadarShowing()) - { - int iAlpha; - g_pCore->GetCVars()->Get("mapalpha", iAlpha); - iAlpha = std::min(255, iAlpha + 20); - g_pCore->GetCVars()->Set("mapalpha", iAlpha); - } + CPlayerMap* playerMap = g_pClientGame->GetPlayerMap(); + if (!playerMap->IsPlayerMapShowing()) + return; + + int mapAlpha; + g_pCore->GetCVars()->Get("mapalpha", mapAlpha); + mapAlpha = std::min(255, mapAlpha + 20); + g_pCore->GetCVars()->Set("mapalpha", mapAlpha); } -void COMMAND_RadarHelp(const char* szCmdLine) +void COMMAND_PlayerMapHelp(const char* szCmdLine) { - g_pClientGame->GetRadarMap()->ToggleHelpText(); + g_pClientGame->GetPlayerMap()->ToggleHelpText(); } void COMMAND_MessageTarget(const char* szCmdLine) diff --git a/Client/mods/deathmatch/ClientCommands.h b/Client/mods/deathmatch/ClientCommands.h index c6aa755099..af31db12d4 100644 --- a/Client/mods/deathmatch/ClientCommands.h +++ b/Client/mods/deathmatch/ClientCommands.h @@ -21,17 +21,17 @@ void COMMAND_ShowNetstat(const char* szCmdLine); void COMMAND_EnterPassenger(const char* szCmdLine); void COMMAND_RadioNext(const char* szCmdLine); void COMMAND_RadioPrevious(const char* szCmdLine); -void COMMAND_RadarMap(const char* szCmdLine); -void COMMAND_RadarZoomIn(const char* szCmdLine); -void COMMAND_RadarZoomOut(const char* szCmdLine); -void COMMAND_RadarMoveNorth(const char* szCmdLine); -void COMMAND_RadarMoveSouth(const char* szCmdLine); -void COMMAND_RadarMoveEast(const char* szCmdLine); -void COMMAND_RadarMoveWest(const char* szCmdLine); -void COMMAND_RadarAttach(const char* szCmdLine); -void COMMAND_RadarOpacityDown(const char* szCmdLine); -void COMMAND_RadarOpacityUp(const char* szCmdLine); -void COMMAND_RadarHelp(const char* szCmdLine); +void COMMAND_PlayerMap(const char* szCmdLine); +void COMMAND_PlayerMapZoomIn(const char* szCmdLine); +void COMMAND_PlayerMapZoomOut(const char* szCmdLine); +void COMMAND_PlayerMapMoveNorth(const char* szCmdLine); +void COMMAND_PlayerMapMoveSouth(const char* szCmdLine); +void COMMAND_PlayerMapMoveEast(const char* szCmdLine); +void COMMAND_PlayerMapMoveWest(const char* szCmdLine); +void COMMAND_PlayerMapAttach(const char* szCmdLine); +void COMMAND_PlayerMapOpacityDown(const char* szCmdLine); +void COMMAND_PlayerMapOpacityUp(const char* szCmdLine); +void COMMAND_PlayerMapHelp(const char* szCmdLine); void COMMAND_MessageTarget(const char* szCmdLine); void COMMAND_VehicleNextWeapon(const char* szCmdLine); void COMMAND_VehiclePreviousWeapon(const char* szCmdLine); diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index a19e878ad5..7678545617 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -135,6 +135,7 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) m_Glitches[GLITCH_BADDRIVEBYHITBOX] = false; m_Glitches[GLITCH_QUICKSTAND] = false; m_Glitches[GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE] = false; + g_pMultiplayer->DisableBadDrivebyHitboxes(true); // Remove Night & Thermal vision view (if enabled). @@ -227,7 +228,7 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) m_pObjectSync = new CObjectSync(m_pObjectManager); #endif m_pNametags = new CNametags(m_pManager); - m_pRadarMap = new CRadarMap(m_pManager); + m_pPlayerMap = new CPlayerMap(m_pManager); // Set the screenshot path /* This is now done in CCore, to maintain a global screenshot path @@ -548,7 +549,7 @@ CClientGame::~CClientGame() #endif SAFE_DELETE(m_pBlendedWeather); SAFE_DELETE(m_pMovingObjectsManager); - SAFE_DELETE(m_pRadarMap); + SAFE_DELETE(m_pPlayerMap); SAFE_DELETE(m_pRemoteCalls); SAFE_DELETE(m_pLuaManager); SAFE_DELETE(m_pLatentTransferManager); @@ -1098,7 +1099,7 @@ void CClientGame::DoPulsePostFrame() CClientPerfStatManager::GetSingleton()->DoPulse(); } - m_pRadarMap->DoRender(); + m_pPlayerMap->DoRender(); m_pManager->DoRender(); DoPulses(); @@ -1436,8 +1437,8 @@ void CClientGame::DoPulses() } // Check for radar input - m_pRadarMap->DoPulse(); - g_pCore->GetGraphics()->SetAspectRatioAdjustmentSuspended(m_pRadarMap->IsRadarShowing()); + m_pPlayerMap->DoPulse(); + g_pCore->GetGraphics()->SetAspectRatioAdjustmentSuspended(m_pPlayerMap->IsPlayerMapShowing()); // Got a local player? if (m_pLocalPlayer) @@ -5407,8 +5408,8 @@ void CClientGame::ResetMapInfo() // Keybinds g_pCore->GetKeyBinds()->SetAllControlsEnabled(true, true, true); - // Radarmap - m_pRadarMap->SetForcedState(false); + // Player map + m_pPlayerMap->SetForcedState(false); // Camera m_pCamera->FadeOut(0.0f, 0, 0, 0); @@ -6026,6 +6027,9 @@ bool CClientGame::SetWorldSpecialProperty(WorldSpecialProperty property, bool is case WorldSpecialProperty::TUNNELWEATHERBLEND: g_pGame->SetTunnelWeatherBlendEnabled(isEnabled); return true; + case WorldSpecialProperty::IGNOREFIRESTATE: + g_pGame->SetIgnoreFireStateEnabled(isEnabled); + return true; } return false; } @@ -6063,6 +6067,8 @@ bool CClientGame::IsWorldSpecialProperty(WorldSpecialProperty property) return g_pGame->IsRoadSignsTextEnabled(); case WorldSpecialProperty::TUNNELWEATHERBLEND: return g_pGame->IsTunnelWeatherBlendEnabled(); + case WorldSpecialProperty::IGNOREFIRESTATE: + return g_pGame->IsIgnoreFireStateEnabled(); } return false; } @@ -6476,7 +6482,7 @@ void CClientGame::OutputServerInfo() { SString strEnabledGlitches; const char* szGlitchNames[] = {"Quick reload", "Fast fire", "Fast move", "Crouch bug", "Close damage", "Hit anim", "Fast sprint", - "Bad driveby hitboxes", "Quick stand"}; + "Bad driveby hitboxes", "Quick stand", "Kickout of vehicle on model replace"}; for (uint i = 0; i < NUM_GLITCHES; i++) { if (IsGlitchEnabled(i)) diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index ba6bc29334..c76dc223aa 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -28,7 +28,7 @@ #include "CUnoccupiedVehicleSync.h" #include "CPedSync.h" #include "CObjectSync.h" -#include "CRadarMap.h" +#include "CPlayerMap.h" #include "CClientTeamManager.h" #include "CClientPedManager.h" #include "lua/CLuaManager.h" @@ -296,7 +296,7 @@ class CClientGame CBlendedWeather* GetBlendedWeather() { return m_pBlendedWeather; }; CNetAPI* GetNetAPI() { return m_pNetAPI; }; - CRadarMap* GetRadarMap() { return m_pRadarMap; }; + CPlayerMap* GetPlayerMap() { return m_pPlayerMap; }; CMovingObjectsManager* GetMovingObjectsManager() { return m_pMovingObjectsManager; } CClientPlayer* GetLocalPlayer() { return m_pLocalPlayer; } @@ -694,7 +694,7 @@ class CClientGame CNetworkStats* m_pNetworkStats; CSyncDebug* m_pSyncDebug; // CScreenshot* m_pScreenshot; - CRadarMap* m_pRadarMap; + CPlayerMap* m_pPlayerMap; CTransferBox* m_pTransferBox; CResourceManager* m_pResourceManager; CScriptKeyBinds* m_pScriptKeyBinds; diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index ebf2ba5140..787cd4c239 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -572,6 +572,10 @@ void CPacketHandler::Packet_ServerDisconnected(NetBitStreamInterface& bitStream) strReason = _("Disconnected: Serial verification failed"); strErrorCode = _E("CD44"); break; + case ePlayerDisconnectType::SERIAL_DUPLICATE: + strReason = _("Disconnected: Serial already in use"); + strErrorCode = _E("CD50"); + break; case ePlayerDisconnectType::CONNECTION_DESYNC: strReason = _("Disconnected: Connection desync %s"); strErrorCode = _E("CD45"); @@ -2393,6 +2397,7 @@ void CPacketHandler::Packet_MapInfo(NetBitStreamInterface& bitStream) g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::ROADSIGNSTEXT, wsProps.data3.roadsignstext); g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::EXTENDEDWATERCANNONS, wsProps.data4.extendedwatercannons); g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::TUNNELWEATHERBLEND, wsProps.data5.tunnelweatherblend); + g_pClientGame->SetWorldSpecialProperty(WorldSpecialProperty::IGNOREFIRESTATE, wsProps.data6.ignoreFireState); float fJetpackMaxHeight = 100; if (!bitStream.Read(fJetpackMaxHeight)) diff --git a/Client/mods/deathmatch/logic/CPacketHandler.h b/Client/mods/deathmatch/logic/CPacketHandler.h index ca0f6f3d69..9a50b24615 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.h +++ b/Client/mods/deathmatch/logic/CPacketHandler.h @@ -42,7 +42,8 @@ class CPacketHandler BAN, KICK, CUSTOM, - SHUTDOWN + SHUTDOWN, + SERIAL_DUPLICATE }; struct SEntityDependantStuff diff --git a/Client/mods/deathmatch/logic/CRadarMap.cpp b/Client/mods/deathmatch/logic/CPlayerMap.cpp similarity index 71% rename from Client/mods/deathmatch/logic/CRadarMap.cpp rename to Client/mods/deathmatch/logic/CPlayerMap.cpp index 4dd01baccd..0653477e5b 100644 --- a/Client/mods/deathmatch/logic/CRadarMap.cpp +++ b/Client/mods/deathmatch/logic/CPlayerMap.cpp @@ -2,8 +2,8 @@ * * PROJECT: Multi Theft Auto v1.0 * LICENSE: See LICENSE in the top level directory - * FILE: mods/deathmatch/logic/CRadarMap.cpp - * PURPOSE: Full screen radar map renderer + * FILE: mods/deathmatch/logic/CPlayerMap.cpp + * PURPOSE: Full screen player map renderer * * Multi Theft Auto is available from http://www.multitheftauto.com/ * @@ -23,15 +23,19 @@ enum MARKER_LAST_SPRITE_INDEX = MARKER_FIRST_SPRITE_INDEX + RADAR_MARKER_LIMIT - 1, }; -CRadarMap::CRadarMap(CClientManager* pManager) +constexpr std::array MAP_IMAGE_SIZES = {1024, 2048}; + +CPlayerMap::CPlayerMap(CClientManager* pManager) { + m_failedToLoadTextures = false; + // Setup our managers m_pManager = pManager; m_pRadarMarkerManager = pManager->GetRadarMarkerManager(); m_pRadarAreaManager = m_pManager->GetRadarAreaManager(); - // Set the radar bools - m_bIsRadarEnabled = false; + // Set the map bools + m_bIsPlayerMapEnabled = false; m_bForcedState = false; m_bIsAttachedToLocal = false; m_bHideHelpText = false; @@ -52,17 +56,13 @@ CRadarMap::CRadarMap(CClientManager* pManager) m_fZoom = 1; m_iHorizontalMovement = 0; m_iVerticalMovement = 0; - SetupMapVariables(); - // Create the radar and local player blip images - m_pRadarImage = - g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(CalcMTASAPath("MTA\\cgui\\images\\radar.jpg"), NULL, false, 1024, 1024, RFORMAT_DXT1); - m_pLocalPlayerBlip = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(CalcMTASAPath("MTA\\cgui\\images\\radarset\\02.png")); - - // Create the marker textures - CreateMarkerTextures(); + // Create all map textures + CreateAllTextures(); // Create the text displays for the help text + const SColorRGBA colorWhiteTransparent(255, 255, 255, 200); + const SColorRGBA colorWhite(255, 255, 255, 255); struct { SColor color; @@ -70,17 +70,15 @@ CRadarMap::CRadarMap(CClientManager* pManager) float fScale; SString strMessage; } messageList[] = { - {SColorRGBA(255, 255, 255, 200), 0.92f, 1.5f, "Current Mode: Kill all humans"}, - {SColorRGBA(255, 255, 255, 255), 0.95f, 1.0f, SString("Press %s to change mode.", *GetBoundKeyName("radar_attach"))}, - {SColorRGBA(255, 255, 255, 255), 0.05f, 1.0f, - SString("Press %s/%s to zoom in/out.", *GetBoundKeyName("radar_zoom_in"), *GetBoundKeyName("radar_zoom_out"))}, - {SColorRGBA(255, 255, 255, 255), 0.08f, 1.0f, - SString("Press %s, %s, %s, %s to navigate the map.", *GetBoundKeyName("radar_move_north"), *GetBoundKeyName("radar_move_east"), - *GetBoundKeyName("radar_move_south"), *GetBoundKeyName("radar_move_west"))}, - {SColorRGBA(255, 255, 255, 255), 0.11f, 1.0f, - SString("Press %s/%s to change opacity.", *GetBoundKeyName("radar_opacity_down"), *GetBoundKeyName("radar_opacity_up"))}, - {SColorRGBA(255, 255, 255, 255), 0.14f, 1.0f, SString("Press %s to hide the map.", *GetBoundKeyName("radar"))}, - {SColorRGBA(255, 255, 255, 255), 0.17f, 1.0f, SString("Press %s to hide this help text.", *GetBoundKeyName("radar_help"))}, + {colorWhiteTransparent, 0.92f, 1.5f, ""}, + {colorWhite, 0.95f, 1.0f, SString(_("Change mode: %s"), *GetBoundKeyName("radar_attach"))}, + + {colorWhite, 0.05f, 1.0f, SString(_("Zoom: %s/%s Movement: %s, %s, %s, %s Opacity: %s/%s"), + *GetBoundKeyName("radar_zoom_in"), *GetBoundKeyName("radar_zoom_out"), *GetBoundKeyName("radar_move_north"), + *GetBoundKeyName("radar_move_east"), *GetBoundKeyName("radar_move_south"), *GetBoundKeyName("radar_move_west"), + *GetBoundKeyName("radar_opacity_down"), *GetBoundKeyName("radar_opacity_up"))}, + {colorWhite, 0.07f, 1.0f, SString(_("Toggle map: %s Toggle help text: %s"), + *GetBoundKeyName("radar"), *GetBoundKeyName("radar_help"))}, }; for (uint i = 0; i < NUMELMS(messageList); i++) @@ -98,26 +96,85 @@ CRadarMap::CRadarMap(CClientManager* pManager) // Default to attached to player SetAttachedToLocalPlayer(true); + + SetupMapVariables(); } -CRadarMap::~CRadarMap() +CPlayerMap::~CPlayerMap() { // Delete our images - SAFE_RELEASE(m_pRadarImage); - SAFE_RELEASE(m_pLocalPlayerBlip); + SAFE_RELEASE(m_mapImageTexture); + SAFE_RELEASE(m_playerMarkerTexture); - for (uint i = 0; i < m_MarkerTextureList.size(); i++) - SAFE_RELEASE(m_MarkerTextureList[i]); + for (uint i = 0; i < m_markerTextureList.size(); i++) + SAFE_RELEASE(m_markerTextureList[i]); - m_MarkerTextureList.clear(); + m_markerTextureList.clear(); // Don't need to delete the help texts as those are destroyed by the display manager } -void CRadarMap::DoPulse() +void CPlayerMap::CreateOrUpdateMapTexture() { - // If our radar image exists - if (IsRadarShowing()) + const std::uint32_t mapSize = MAP_IMAGE_SIZES[m_playerMapImageIndex]; + const SString fileName("MTA\\cgui\\images\\map_%d.png", mapSize); + + auto* newTexture = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(CalcMTASAPath(fileName), nullptr, false, mapSize, mapSize, RFORMAT_DXT1); + if (!newTexture) + throw std::runtime_error("Failed to load map image"); + + SAFE_RELEASE(m_mapImageTexture); + m_mapImageTexture = newTexture; +} + +void CPlayerMap::UpdateOrRevertMapTexture(std::size_t newImageIndex) +{ + const std::size_t oldImageIndex = m_playerMapImageIndex; + try + { + m_playerMapImageIndex = newImageIndex; + CreateOrUpdateMapTexture(); + } + catch (const std::exception& e) + { + m_playerMapImageIndex = oldImageIndex; + g_pCore->GetConsole()->Printf("Problem updating map image: %s", e.what()); + } +} + +void CPlayerMap::CreatePlayerBlipTexture() +{ + m_playerMarkerTexture = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(CalcMTASAPath("MTA\\cgui\\images\\radarset\\02.png")); + if (!m_playerMarkerTexture) + throw std::runtime_error("Failed to load player blip image"); +} + +void CPlayerMap::CreateAllTextures() +{ + try + { + // Create the map texture + m_mapImageTexture = nullptr; + m_playerMapImageIndex = g_pCore->GetCVars()->GetValue("mapimage"); + CreateOrUpdateMapTexture(); + + // Create the player blip texture + CreatePlayerBlipTexture(); + + // Create the other marker textures + CreateMarkerTextures(); + } + catch (const std::exception& e) + { + m_failedToLoadTextures = true; + g_pCore->GetConsole()->Printf("Problem initializing player map: %s", e.what()); + } +} + +void CPlayerMap::DoPulse() +{ + // If our map image exists + if (IsPlayerMapShowing()) { // If we are following the local player blip if (m_bIsAttachedToLocal) @@ -154,11 +211,11 @@ void CRadarMap::DoPulse() } // -// Precreate all the textures for the radar map markers +// Precreate all the textures for the player map markers // -void CRadarMap::CreateMarkerTextures() +void CPlayerMap::CreateMarkerTextures() { - assert(m_MarkerTextureList.empty()); + m_markerTextureList.clear(); SString strRadarSetDirectory = CalcMTASAPath("MTA\\cgui\\images\\radarset\\"); // Load the 3 shapes @@ -166,25 +223,27 @@ void CRadarMap::CreateMarkerTextures() for (uint i = 0; i < NUMELMS(shapeFileNames); i++) { CTextureItem* pTextureItem = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(PathJoin(strRadarSetDirectory, shapeFileNames[i])); - m_MarkerTextureList.push_back(pTextureItem); + m_markerTextureList.push_back(pTextureItem); } - assert(m_MarkerTextureList.size() == MARKER_FIRST_SPRITE_INDEX); + if (m_markerTextureList.size() != MARKER_FIRST_SPRITE_INDEX) + throw std::runtime_error("Failed to load marker textures [1]"); // Load the icons for (uint i = 0; i < RADAR_MARKER_LIMIT; i++) { CTextureItem* pTextureItem = g_pCore->GetGraphics()->GetRenderItemManager()->CreateTexture(PathJoin(strRadarSetDirectory, SString("%02u.png", i + 1))); - m_MarkerTextureList.push_back(pTextureItem); + m_markerTextureList.push_back(pTextureItem); } - assert(m_MarkerTextureList.size() == MARKER_LAST_SPRITE_INDEX + 1); + if (m_markerTextureList.size() != MARKER_LAST_SPRITE_INDEX + 1) + throw std::runtime_error("Failed to load marker textures [2]"); } // // Get a texture for a marker, including scale and color // -CTextureItem* CRadarMap::GetMarkerTexture(CClientRadarMarker* pMarker, float fLocalZ, float* pfScale, SColor* pColor) +CTextureItem* CPlayerMap::GetMarkerTexture(CClientRadarMarker* pMarker, float fLocalZ, float* pfScale, SColor* pColor) { float fScale = pMarker->GetScale(); ulong ulSprite = pMarker->GetSprite(); @@ -220,26 +279,33 @@ CTextureItem* CRadarMap::GetMarkerTexture(CClientRadarMarker* pMarker, float fLo *pfScale = fScale; *pColor = color; - if (uiListIndex >= m_MarkerTextureList.size()) + if (uiListIndex >= m_markerTextureList.size()) return NULL; - return m_MarkerTextureList[uiListIndex]; + return m_markerTextureList[uiListIndex]; } -void CRadarMap::DoRender() +void CPlayerMap::DoRender() { - bool bIsRadarShowing = IsRadarShowing(); + bool isMapShowing = IsPlayerMapShowing(); - // Render if showing - if (bIsRadarShowing) + // Render if showing and textures are all loaded + if (isMapShowing && !m_failedToLoadTextures) { // Get the alpha value from the settings - int iRadarAlpha; - g_pCore->GetCVars()->Get("mapalpha", iRadarAlpha); + int mapAlpha; + g_pCore->GetCVars()->Get("mapalpha", mapAlpha); + const SColorARGB mapColor(mapAlpha, 255, 255, 255); + + // Update the image if the user changed it via a setting + auto mapImageIndex = g_pCore->GetCVars()->GetValue("mapimage"); + if (mapImageIndex != m_playerMapImageIndex) + { + UpdateOrRevertMapTexture(mapImageIndex); + } - g_pCore->GetGraphics()->DrawTexture(m_pRadarImage, static_cast(m_iMapMinX), static_cast(m_iMapMinY), - m_fMapSize / m_pRadarImage->m_uiSizeX, m_fMapSize / m_pRadarImage->m_uiSizeY, 0.0f, 0.0f, 0.0f, - SColorARGB(iRadarAlpha, 255, 255, 255)); + g_pCore->GetGraphics()->DrawTexture(m_mapImageTexture, static_cast(m_iMapMinX), static_cast(m_iMapMinY), + m_fMapSize / m_mapImageTexture->m_uiSizeX, m_fMapSize / m_mapImageTexture->m_uiSizeY, 0.0f, 0.0f, 0.0f, mapColor); // Grab the info for the local player blip CVector2D vecLocalPos; @@ -316,11 +382,11 @@ void CRadarMap::DoRender() } } - g_pCore->GetGraphics()->DrawTexture(m_pLocalPlayerBlip, vecLocalPos.fX, vecLocalPos.fY, 1.0, 1.0, vecLocalRot.fZ, 0.5f, 0.5f); + g_pCore->GetGraphics()->DrawTexture(m_playerMarkerTexture, vecLocalPos.fX, vecLocalPos.fY, 1.0, 1.0, vecLocalRot.fZ, 0.5f, 0.5f); } // Update visibility of help text - bool bRequiredTextVisible = bIsRadarShowing && !m_bHideHelpText; + bool bRequiredTextVisible = isMapShowing && !m_bHideHelpText; if (bRequiredTextVisible != m_bTextVisible) { m_bTextVisible = bRequiredTextVisible; @@ -331,31 +397,31 @@ void CRadarMap::DoRender() } } -void CRadarMap::SetRadarEnabled(bool bIsRadarEnabled) +void CPlayerMap::SetPlayerMapEnabled(bool show) { - bool bAlreadyEnabled = (m_bIsRadarEnabled || m_bForcedState); - bool bWillShow = (bIsRadarEnabled || m_bForcedState); - if (bAlreadyEnabled != bWillShow) + bool alreadyEnabled = (m_bIsPlayerMapEnabled || m_bForcedState); + bool definitiveShow = (show || m_bForcedState); + if (alreadyEnabled != definitiveShow) { - InternalSetRadarEnabled(bWillShow); + InternalSetPlayerMapEnabled(definitiveShow); } - m_bIsRadarEnabled = bIsRadarEnabled; + m_bIsPlayerMapEnabled = show; } -void CRadarMap::SetForcedState(bool bState) +void CPlayerMap::SetForcedState(bool state) { - bool bAlreadyShowing = (m_bIsRadarEnabled || m_bForcedState); - bool bWillShow = (m_bIsRadarEnabled || bState); - if (bAlreadyShowing != bWillShow) + bool currState = (m_bIsPlayerMapEnabled || m_bForcedState); + bool definitiveState = (m_bIsPlayerMapEnabled || state); + if (currState != definitiveState) { - InternalSetRadarEnabled(bWillShow); + InternalSetPlayerMapEnabled(definitiveState); } - m_bForcedState = bState; + m_bForcedState = state; } -void CRadarMap::InternalSetRadarEnabled(bool bEnabled) +void CPlayerMap::InternalSetPlayerMapEnabled(bool enable) { - if (bEnabled) + if (enable) { m_bChatVisible = g_pCore->IsChatVisible(); m_bChatInputBlocked = g_pCore->IsChatInputBlocked(); @@ -375,7 +441,7 @@ void CRadarMap::InternalSetRadarEnabled(bool bEnabled) } } -bool CRadarMap::CalculateEntityOnScreenPosition(CClientEntity* pEntity, CVector2D& vecLocalPos) +bool CPlayerMap::CalculateEntityOnScreenPosition(CClientEntity* pEntity, CVector2D& vecLocalPos) { // If the entity exists if (pEntity) @@ -406,7 +472,7 @@ bool CRadarMap::CalculateEntityOnScreenPosition(CClientEntity* pEntity, CVector2 return false; } -bool CRadarMap::CalculateEntityOnScreenPosition(CVector vecPosition, CVector2D& vecLocalPos) +bool CPlayerMap::CalculateEntityOnScreenPosition(CVector vecPosition, CVector2D& vecLocalPos) { // Adjust to the map variables and create the map ratio float fX = vecPosition.fX + 3000.0f; @@ -428,7 +494,7 @@ bool CRadarMap::CalculateEntityOnScreenPosition(CVector vecPosition, CVector2D& return false; } -void CRadarMap::SetupMapVariables() +void CPlayerMap::SetupMapVariables() { // Calculate the map size and the middle of the screen coords m_fMapSize = static_cast(m_uiHeight * m_fZoom); @@ -524,7 +590,7 @@ void CRadarMap::SetupMapVariables() } } -void CRadarMap::ZoomIn() +void CPlayerMap::ZoomIn() { if (m_fZoom <= 4) { @@ -533,7 +599,7 @@ void CRadarMap::ZoomIn() } } -void CRadarMap::ZoomOut() +void CPlayerMap::ZoomOut() { if (m_fZoom >= 1) { @@ -559,7 +625,7 @@ void CRadarMap::ZoomOut() } } -void CRadarMap::MoveNorth() +void CPlayerMap::MoveNorth() { if (!m_bIsAttachedToLocal) { @@ -579,7 +645,7 @@ void CRadarMap::MoveNorth() } } -void CRadarMap::MoveSouth() +void CPlayerMap::MoveSouth() { if (!m_bIsAttachedToLocal) { @@ -599,7 +665,7 @@ void CRadarMap::MoveSouth() } } -void CRadarMap::MoveEast() +void CPlayerMap::MoveEast() { if (!m_bIsAttachedToLocal) { @@ -619,7 +685,7 @@ void CRadarMap::MoveEast() } } -void CRadarMap::MoveWest() +void CPlayerMap::MoveWest() { if (!m_bIsAttachedToLocal) { @@ -639,30 +705,26 @@ void CRadarMap::MoveWest() } } -void CRadarMap::SetAttachedToLocalPlayer(bool bIsAttachedToLocal) +void CPlayerMap::SetAttachedToLocalPlayer(bool bIsAttachedToLocal) { m_bIsAttachedToLocal = bIsAttachedToLocal; SetupMapVariables(); if (m_bIsAttachedToLocal) - { - m_HelpTextList[0]->SetCaption("Current Mode: Attached to local player"); - } + m_HelpTextList[0]->SetCaption(_("Following Player")); else - { - m_HelpTextList[0]->SetCaption("Current Mode: Free Move"); - } + m_HelpTextList[0]->SetCaption(_("Free Movement")); } -bool CRadarMap::IsRadarShowing() +bool CPlayerMap::IsPlayerMapShowing() { - return ((m_bIsRadarEnabled || m_bForcedState) && m_pRadarImage && m_pLocalPlayerBlip && (!g_pCore->GetConsole()->IsVisible() && !g_pCore->IsMenuVisible())); + return ((m_bIsPlayerMapEnabled || m_bForcedState) && m_mapImageTexture && m_playerMarkerTexture && (!g_pCore->GetConsole()->IsVisible() && !g_pCore->IsMenuVisible())); } -bool CRadarMap::GetBoundingBox(CVector& vecMin, CVector& vecMax) +bool CPlayerMap::GetBoundingBox(CVector& vecMin, CVector& vecMax) { - // If our radar image exists (Values are not calculated unless map is showing) - if (IsRadarShowing()) + // If our map image exists (Values are not calculated unless map is showing) + if (IsPlayerMapShowing()) { vecMin.fX = static_cast(m_iMapMinX); vecMin.fY = static_cast(m_iMapMinY); @@ -678,12 +740,12 @@ bool CRadarMap::GetBoundingBox(CVector& vecMin, CVector& vecMax) } } -void CRadarMap::ToggleHelpText() +void CPlayerMap::ToggleHelpText() { m_bHideHelpText = !m_bHideHelpText; } -SString CRadarMap::GetBoundKeyName(const SString& strCommand) +SString CPlayerMap::GetBoundKeyName(const SString& strCommand) { CCommandBind* pCommandBind = g_pCore->GetKeyBinds()->GetBindFromCommand(strCommand, 0, 0, 0, false, 0); if (!pCommandBind) diff --git a/Client/mods/deathmatch/logic/CRadarMap.h b/Client/mods/deathmatch/logic/CPlayerMap.h similarity index 77% rename from Client/mods/deathmatch/logic/CRadarMap.h rename to Client/mods/deathmatch/logic/CPlayerMap.h index a3dd8f0d51..0d6edebb6f 100644 --- a/Client/mods/deathmatch/logic/CRadarMap.h +++ b/Client/mods/deathmatch/logic/CPlayerMap.h @@ -2,8 +2,8 @@ * * PROJECT: Multi Theft Auto v1.0 * LICENSE: See LICENSE in the top level directory - * FILE: mods/deathmatch/logic/CRadarMap.h - * PURPOSE: Header for radar map class + * FILE: mods/deathmatch/logic/CPlayerMap.h + * PURPOSE: Header for player map class * * Multi Theft Auto is available from http://www.multitheftauto.com/ * @@ -16,19 +16,19 @@ #include #include -class CRadarMap +class CPlayerMap { public: - CRadarMap(class CClientManager* pManager); - virtual ~CRadarMap(); + CPlayerMap(class CClientManager* pManager); + virtual ~CPlayerMap(); void DoPulse(); void DoRender(); - bool IsRadarShowing(); + bool IsPlayerMapShowing(); - bool GetRadarEnabled() const { return m_bIsRadarEnabled; }; - void SetRadarEnabled(bool bIsRadarEnabled); + bool GetPlayerMapEnabled() const { return m_bIsPlayerMapEnabled; }; + void SetPlayerMapEnabled(bool bIsRadarEnabled); bool GetForcedState() const { return m_bForcedState; } void SetForcedState(bool bState); @@ -38,10 +38,14 @@ class CRadarMap void ToggleHelpText(); protected: - void InternalSetRadarEnabled(bool bEnabled); + void InternalSetPlayerMapEnabled(bool bEnabled); void CreateMarkerTextures(); CTextureItem* GetMarkerTexture(CClientRadarMarker* pMarker, float fLocalZ, float* pfScale, SColor* pColor); + void CreatePlayerBlipTexture(); + void CreateOrUpdateMapTexture(); + void UpdateOrRevertMapTexture(std::size_t imageIndex); + void CreateAllTextures(); public: bool IsAttachedToLocalPlayer() const { return m_bIsAttachedToLocal; }; @@ -79,9 +83,13 @@ class CRadarMap class CClientRadarMarkerManager* m_pRadarMarkerManager; class CClientRadarAreaManager* m_pRadarAreaManager; - CTextureItem* m_pRadarImage; - CTextureItem* m_pLocalPlayerBlip; - std::vector m_MarkerTextureList; + bool m_failedToLoadTextures; + + std::size_t m_playerMapImageIndex; + + CTextureItem* m_mapImageTexture; + CTextureItem* m_playerMarkerTexture; + std::vector m_markerTextureList; unsigned int m_uiHeight; unsigned int m_uiWidth; @@ -97,7 +105,7 @@ class CRadarMap float m_fZoom; - bool m_bIsRadarEnabled; + bool m_bIsPlayerMapEnabled; bool m_bForcedState; bool m_bIsAttachedToLocal; diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 5efe5b417e..5612bd9976 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -51,7 +51,7 @@ static CClientMarkerManager* m_pMarkerManager; static CClientPickupManager* m_pPickupManager; static CMovingObjectsManager* m_pMovingObjectsManager; static CBlendedWeather* m_pBlendedWeather; -static CRadarMap* m_pRadarMap; +static CPlayerMap* m_pPlayerMap; static CClientCamera* m_pCamera; static CClientExplosionManager* m_pExplosionManager; static CClientProjectileManager* m_pProjectileManager; @@ -88,7 +88,7 @@ CStaticFunctionDefinitions::CStaticFunctionDefinitions(CLuaManager* pLuaManager, m_pPickupManager = pManager->GetPickupManager(); m_pMovingObjectsManager = m_pClientGame->GetMovingObjectsManager(); m_pBlendedWeather = m_pClientGame->GetBlendedWeather(); - m_pRadarMap = m_pClientGame->GetRadarMap(); + m_pPlayerMap = m_pClientGame->GetPlayerMap(); m_pCamera = pManager->GetCamera(); m_pExplosionManager = pManager->GetExplosionManager(); m_pProjectileManager = pManager->GetProjectileManager(); @@ -7840,25 +7840,25 @@ bool CStaticFunctionDefinitions::SetWeaponClipAmmo(CClientWeapon* pWeapon, int i bool CStaticFunctionDefinitions::ForcePlayerMap(bool& bForced) { - m_pClientGame->GetRadarMap()->SetForcedState(bForced); + m_pClientGame->GetPlayerMap()->SetForcedState(bForced); return true; } bool CStaticFunctionDefinitions::IsPlayerMapForced(bool& bForced) { - bForced = m_pRadarMap->GetForcedState(); + bForced = m_pPlayerMap->GetForcedState(); return true; } bool CStaticFunctionDefinitions::IsPlayerMapVisible(bool& bVisible) { - bVisible = m_pRadarMap->IsRadarShowing(); + bVisible = m_pPlayerMap->IsPlayerMapShowing(); return true; } bool CStaticFunctionDefinitions::GetPlayerMapBoundingBox(CVector& vecMin, CVector& vecMax) { - if (m_pRadarMap->GetBoundingBox(vecMin, vecMax)) + if (m_pPlayerMap->GetBoundingBox(vecMin, vecMax)) { return true; } diff --git a/Client/mods/deathmatch/logic/rpc/CPlayerRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CPlayerRPCs.cpp index e8cda43283..321c030652 100644 --- a/Client/mods/deathmatch/logic/rpc/CPlayerRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CPlayerRPCs.cpp @@ -60,7 +60,7 @@ void CPlayerRPCs::ForcePlayerMap(NetBitStreamInterface& bitStream) if (bitStream.Read(ucVisible)) { bool bVisible = (ucVisible == 1); - m_pClientGame->GetRadarMap()->SetForcedState(bVisible); + m_pClientGame->GetPlayerMap()->SetForcedState(bVisible); } } diff --git a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp index d92ba4788b..fd305f6955 100644 --- a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp @@ -619,6 +619,8 @@ void CWorldRPCs::SetSyncIntervals(NetBitStreamInterface& bitStream) bitStream.Read(g_TickRateSettings.iObjectSync); bitStream.Read(g_TickRateSettings.iKeySyncRotation); bitStream.Read(g_TickRateSettings.iKeySyncAnalogMove); + bitStream.Read(g_TickRateSettings.iPedSyncerDistance); + bitStream.Read(g_TickRateSettings.iUnoccupiedVehicleSyncerDistance); } void CWorldRPCs::SetMoonSize(NetBitStreamInterface& bitStream) diff --git a/Client/multiplayer_sa/CMultiplayerSA.cpp b/Client/multiplayer_sa/CMultiplayerSA.cpp index 0268688823..f6733a3cb6 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA.cpp @@ -1574,6 +1574,7 @@ void CMultiplayerSA::InitHooks() MemSet((void*)0x6C4453, 0x90, 0x68); InitHooks_CrashFixHacks(); + InitHooks_DeviceSelection(); // Init our 1.3 hooks. Init_13(); @@ -1861,6 +1862,7 @@ void CMultiplayerSA::DisableCloseRangeDamage(bool bDisabled) MemPut(0x73BA00, 0x86); } } + bool CMultiplayerSA::GetInteriorSoundsEnabled() { return bInteriorSoundsEnabled; diff --git a/Client/multiplayer_sa/CMultiplayerSA.h b/Client/multiplayer_sa/CMultiplayerSA.h index 802b9b56ea..d97300e6a1 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.h +++ b/Client/multiplayer_sa/CMultiplayerSA.h @@ -80,6 +80,7 @@ class CMultiplayerSA : public CMultiplayer void InitHooks_ProjectileCollisionFix(); void InitHooks_ObjectStreamerOptimization(); void InitHooks_Postprocess(); + void InitHooks_DeviceSelection(); CRemoteDataStorage* CreateRemoteDataStorage(); void DestroyRemoteDataStorage(CRemoteDataStorage* pData); void AddRemoteDataStorage(CPlayerPed* pPed, CRemoteDataStorage* pData); diff --git a/Client/multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp b/Client/multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp new file mode 100644 index 0000000000..586f387270 --- /dev/null +++ b/Client/multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp @@ -0,0 +1,155 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto v1.0 + * LICENSE: See LICENSE in the top level directory + * FILE: multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#define FUNC_rwDeviceSystemRequest 0x7F2AB0 +#define FUNC_DialogFunc 0x745E50 +#define FUNC_RwEngineGetSubSystemInfo 0x7F2C30 +#define CLASS_RwGlobals 0xC97B24 +#define CLASS_IDirect3D9 0xC97C20 +#define NUM_DialogFuncStackPushAddress 0x746239 + +// This is copied from SilentPatch: +// https://github.com/CookiePLMonster/SilentPatch/blob/dev/SilentPatch/FriendlyMonitorNames.cpp +std::unordered_map GetFriendlyMonitorNamesForDevicePaths() +{ + std::unordered_map monitorNames; + + HMODULE user32Lib = LoadLibrary(TEXT("user32")); + if (!user32Lib) + return monitorNames; + + auto* getDisplayConfigBufferSizes = (decltype(GetDisplayConfigBufferSizes)*)GetProcAddress(user32Lib, "GetDisplayConfigBufferSizes"); + auto* queryDisplayConfig = (decltype(QueryDisplayConfig)*)GetProcAddress(user32Lib, "QueryDisplayConfig"); + auto* displayConfigGetDeviceInfo = (decltype(DisplayConfigGetDeviceInfo)*)GetProcAddress(user32Lib, "DisplayConfigGetDeviceInfo"); + if (!getDisplayConfigBufferSizes || !queryDisplayConfig || !displayConfigGetDeviceInfo) + { + FreeLibrary(user32Lib); + return monitorNames; + } + + UINT32 pathCount, modeCount; + std::unique_ptr paths; + std::unique_ptr modes; + + LONG result = ERROR_SUCCESS; + do + { + result = getDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount); + if (result != ERROR_SUCCESS) + { + break; + } + paths = std::make_unique(pathCount); + modes = std::make_unique(modeCount); + result = queryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.get(), &modeCount, modes.get(), nullptr); + } while (result == ERROR_INSUFFICIENT_BUFFER); + + if (result != ERROR_SUCCESS) + { + FreeLibrary(user32Lib); + return monitorNames; + } + + for (size_t i = 0; i < pathCount; i++) + { + DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {}; + targetName.header.adapterId = paths[i].targetInfo.adapterId; + targetName.header.id = paths[i].targetInfo.id; + targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + targetName.header.size = sizeof(targetName); + const LONG targetNameResult = DisplayConfigGetDeviceInfo(&targetName.header); + + DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = {}; + sourceName.header.adapterId = paths[i].sourceInfo.adapterId; + sourceName.header.id = paths[i].sourceInfo.id; + sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + sourceName.header.size = sizeof(sourceName); + const LONG sourceNameResult = DisplayConfigGetDeviceInfo(&sourceName.header); + if (targetNameResult == ERROR_SUCCESS && sourceNameResult == ERROR_SUCCESS && targetName.monitorFriendlyDeviceName[0] != '\0') + { + char gdiDeviceName[std::size(sourceName.viewGdiDeviceName)]; + char monitorFriendlyDeviceName[std::size(targetName.monitorFriendlyDeviceName)]; + WideCharToMultiByte(CP_ACP, 0, sourceName.viewGdiDeviceName, -1, gdiDeviceName, static_cast(std::size(gdiDeviceName)), nullptr, nullptr); + WideCharToMultiByte(CP_ACP, 0, targetName.monitorFriendlyDeviceName, -1, monitorFriendlyDeviceName, + static_cast(std::size(monitorFriendlyDeviceName)), nullptr, nullptr); + + monitorNames.try_emplace(gdiDeviceName, monitorFriendlyDeviceName); + } + } + + FreeLibrary(user32Lib); + return monitorNames; +} + +struct RwSubSystemInfo +{ + char name[80]; +}; + +using rwDeviceSystemRequest = RwSubSystemInfo*(__cdecl*)(RwDevice* device, std::int32_t requestId, RwSubSystemInfo* pOut, void* pInOut, std::int32_t numIn); +static RwSubSystemInfo* RwEngineGetSubSystemInfo_Hooked(RwSubSystemInfo* subSystemInfo, std::int32_t subSystemIndex) +{ + auto* rwGlobals = *(RwGlobals**)CLASS_RwGlobals; + auto* rwDeviceSystemRequestFunc = (rwDeviceSystemRequest)(FUNC_rwDeviceSystemRequest); + if (!rwDeviceSystemRequestFunc(&rwGlobals->dOpenDevice, 14, subSystemInfo, nullptr, subSystemIndex)) + return nullptr; + + auto* pDxDevice = *(IDirect3D9**)CLASS_IDirect3D9; + if (!pDxDevice) + return subSystemInfo; + + D3DADAPTER_IDENTIFIER9 identifier; + if (FAILED(pDxDevice->GetAdapterIdentifier(subSystemIndex, 0, &identifier))) + return subSystemInfo; + + static const auto friendlyNames = GetFriendlyMonitorNamesForDevicePaths(); + + // If we can't find the friendly name, either because it doesn't exist or we're on an ancient Windows, fall back to the device name + auto it = friendlyNames.find(identifier.DeviceName); + if (it != friendlyNames.end()) + { + strncpy_s(subSystemInfo->name, it->second.c_str(), _TRUNCATE); + } + else + { + strncpy_s(subSystemInfo->name, identifier.Description, _TRUNCATE); + } + + return subSystemInfo; +} + +INT_PTR CALLBACK CustomDlgProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) +{ + auto* orgDialogFunc = (DLGPROC)FUNC_DialogFunc; + if (msg != WM_INITDIALOG) + return orgDialogFunc(window, msg, wParam, lParam); + + orgDialogFunc(window, msg, wParam, lParam); + + // Set Icon + HMODULE hGameModule = GetModuleHandle(nullptr); + SendMessage(window, WM_SETICON, ICON_SMALL, reinterpret_cast(LoadIcon(hGameModule, MAKEINTRESOURCE(100)))); + + // Make the dialog visible in the task bar + // https://stackoverflow.com/a/1462811 + SetWindowLongPtr(window, GWL_EXSTYLE, WS_EX_APPWINDOW); + ShowWindow(window, SW_HIDE); + ShowWindow(window, SW_SHOW); + return FALSE; +} + +void CMultiplayerSA::InitHooks_DeviceSelection() +{ + // 0x746239 -> Exact address where the original DialogFunc address is being pushed as an argument to DialogBoxParamA(), + // we're replacing it with out own proxy function + MemPut(NUM_DialogFuncStackPushAddress, (DLGPROC)&CustomDlgProc); + HookInstall(FUNC_RwEngineGetSubSystemInfo, (DWORD)RwEngineGetSubSystemInfo_Hooked, 6); +} diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index 2314fdad0e..06866e06ce 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -230,6 +230,9 @@ class __declspec(novtable) CGame virtual bool IsTunnelWeatherBlendEnabled() const noexcept = 0; virtual void SetTunnelWeatherBlendEnabled(bool isEnabled) = 0; + virtual bool IsIgnoreFireStateEnabled() const noexcept = 0; + virtual void SetIgnoreFireStateEnabled(bool isEnabled) = 0; + virtual CWeapon* CreateWeapon() = 0; virtual CWeaponStat* CreateWeaponStat(eWeaponType weaponType, eWeaponSkill weaponSkill) = 0; diff --git a/Client/sdk/game/RenderWare.h b/Client/sdk/game/RenderWare.h index 20249e01fd..d85011b291 100644 --- a/Client/sdk/game/RenderWare.h +++ b/Client/sdk/game/RenderWare.h @@ -526,3 +526,49 @@ struct RwError { int err1, err2; }; + +/*****************************************************************************/ +/** RenderWare Globals **/ +/*****************************************************************************/ + +typedef bool (*RwSystemFunc)(std::int32_t, void*, void*, std::int32_t); +struct RwDevice +{ + float gammaCorrection; + RwSystemFunc fpSystem; + float zBufferNear; + float zBufferFar; + // RwRenderStateSetFunction fpRenderStateSet; + // RwRenderStateGetFunction fpRenderStateGet; + // RwIm2DRenderLineFunction fpIm2DRenderLine; + // RwIm2DRenderTriangleFunction fpIm2DRenderTriangle; + // RwIm2DRenderPrimitiveFunction fpIm2DRenderPrimitive; + // RwIm2DRenderIndexedPrimitiveFunction fpIm2DRenderIndexedPrimitive; + // RwIm3DRenderLineFunction fpIm3DRenderLine; + // RwIm3DRenderTriangleFunction fpIm3DRenderTriangle; + // RwIm3DRenderPrimitiveFunction fpIm3DRenderPrimitive; + // RwIm3DRenderIndexedPrimitiveFunction fpIm3DRenderIndexedPrimitive; +}; +// static_assert(sizeof(RwDevice) == 0x38, "Incorrect class size: RwDevice"); + +typedef bool (*RwStandardFunc)(void*, void*, std::int32_t); +struct RwGlobals +{ + void* curCamera; + void* curWorld; + std::uint16_t renderFrame; + std::uint16_t lightFrame; + std::uint16_t pad[2]; + RwDevice dOpenDevice; + RwStandardFunc stdFunc[29]; + // RwLinkList dirtyFrameList; + // RwFileFunctions fileFuncs; + // RwStringFunctions stringFuncs; + // RwMemoryFunctions memoryFuncs; + // RwMemoryAllocFn memoryAlloc; + // RwMemoryFreeFn memoryFree; + // RwMetrics* metrics; + // RwEngineStatus engineStatus; + // RwUInt32 resArenaInitSize; +}; +//static_assert(sizeof(RwGlobals) == 0x158, "Incorrect class size: RwGlobals"); diff --git a/Server/mods/deathmatch/StdInc.h b/Server/mods/deathmatch/StdInc.h index c2e6355739..fb397aad5b 100644 --- a/Server/mods/deathmatch/StdInc.h +++ b/Server/mods/deathmatch/StdInc.h @@ -49,6 +49,7 @@ #include #include #include +#include "version.h" extern class CNetServer* g_pRealNetServer; extern class CGame* g_pGame; diff --git a/Server/mods/deathmatch/editor.conf b/Server/mods/deathmatch/editor.conf index 3b2b75fa80..1355e673ee 100644 --- a/Server/mods/deathmatch/editor.conf +++ b/Server/mods/deathmatch/editor.conf @@ -268,6 +268,12 @@ Values: 0 - Off, 1 - Enabled. Default - 1 --> 1 + + 1 + diff --git a/Server/mods/deathmatch/local.conf b/Server/mods/deathmatch/local.conf index 039e155d81..d30a608781 100644 --- a/Server/mods/deathmatch/local.conf +++ b/Server/mods/deathmatch/local.conf @@ -274,6 +274,12 @@ Values: 0 - Off, 1 - Enabled. Default - 0 --> 0 + + 1 + diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 9543e1e447..98ea8250b2 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -258,6 +258,7 @@ CGame::CGame() : m_FloodProtect(4, 30000, 30000) // Max of 4 connecti m_WorldSpecialProps[WorldSpecialProperty::EXTENDEDWATERCANNONS] = true; m_WorldSpecialProps[WorldSpecialProperty::ROADSIGNSTEXT] = true; m_WorldSpecialProps[WorldSpecialProperty::TUNNELWEATHERBLEND] = true; + m_WorldSpecialProps[WorldSpecialProperty::IGNOREFIRESTATE] = false; m_JetpackWeapons[WEAPONTYPE_MICRO_UZI] = true; m_JetpackWeapons[WEAPONTYPE_TEC9] = true; @@ -1798,6 +1799,21 @@ void CGame::Packet_PlayerJoinData(CPlayerJoinDataPacket& Packet) return; } + // Check if another player is using the same serial + if (m_pMainConfig->IsCheckDuplicateSerialsEnabled() && m_pPlayerManager->GetBySerial(strSerial)) + { + // Tell the console + CLogger::LogPrintf("CONNECT: %s failed to connect (Serial already in use) (%s)\n", szNick, strIPAndSerial.c_str()); + + // Tell the player the problem + if (pPlayer->CanBitStream(eBitStreamVersion::CheckDuplicateSerials)) + DisconnectPlayer(this, *pPlayer, CPlayerDisconnectedPacket::SERIAL_DUPLICATE); + else + DisconnectPlayer(this, *pPlayer, CPlayerDisconnectedPacket::KICK); + + return; + } + // Check the nick is valid if (!CheckNickProvided(szNick)) { diff --git a/Server/mods/deathmatch/logic/CMainConfig.cpp b/Server/mods/deathmatch/logic/CMainConfig.cpp index bece65e885..49c73419ca 100644 --- a/Server/mods/deathmatch/logic/CMainConfig.cpp +++ b/Server/mods/deathmatch/logic/CMainConfig.cpp @@ -80,6 +80,7 @@ CMainConfig::CMainConfig(CConsole* pConsole) : CXMLConfig(NULL) m_iBackupAmount = 5; m_bSyncMapElementData = true; m_elementDataWhitelisted = false; + m_checkDuplicateSerials = true; } bool CMainConfig::Load() @@ -528,6 +529,7 @@ bool CMainConfig::Load() } GetBoolean(m_pRootNode, "elementdata_whitelisted", m_elementDataWhitelisted); + GetBoolean(m_pRootNode, "check_duplicate_serials", m_checkDuplicateSerials); ApplyNetOptions(); diff --git a/Server/mods/deathmatch/logic/CMainConfig.h b/Server/mods/deathmatch/logic/CMainConfig.h index 9758ae2dbf..05df0e2f32 100644 --- a/Server/mods/deathmatch/logic/CMainConfig.h +++ b/Server/mods/deathmatch/logic/CMainConfig.h @@ -127,6 +127,7 @@ class CMainConfig : public CXMLConfig bool IsDatabaseCredentialsProtectionEnabled() const { return m_bDatabaseCredentialsProtectionEnabled != 0; } bool IsFakeLagCommandEnabled() const { return m_bFakeLagCommandEnabled != 0; } bool IsElementDataWhitelisted() const { return m_elementDataWhitelisted; } + bool IsCheckDuplicateSerialsEnabled() const noexcept { return m_checkDuplicateSerials; } bool IsCheckResourceClientFilesEnabled() const noexcept { return m_checkResourceClientFiles != 0; } SString GetSetting(const SString& configSetting); @@ -230,5 +231,6 @@ class CMainConfig : public CXMLConfig int m_iPlayerTriggeredEventIntervalMs; int m_iMaxPlayerTriggeredEventsPerInterval; bool m_elementDataWhitelisted; + bool m_checkDuplicateSerials; int m_checkResourceClientFiles; }; diff --git a/Server/mods/deathmatch/logic/CPlayerManager.cpp b/Server/mods/deathmatch/logic/CPlayerManager.cpp index abdf923df7..227d3677f2 100644 --- a/Server/mods/deathmatch/logic/CPlayerManager.cpp +++ b/Server/mods/deathmatch/logic/CPlayerManager.cpp @@ -138,6 +138,17 @@ CPlayer* CPlayerManager::Get(const char* szNick, bool bCaseSensitive) return NULL; } +CPlayer* CPlayerManager::GetBySerial(const std::string_view serial) const noexcept +{ + for (const auto& player : m_Players) + { + if (player->GetSerial() == serial) + return player; + } + + return nullptr; +} + void CPlayerManager::DeleteAll() { // Delete all the items in the list diff --git a/Server/mods/deathmatch/logic/CPlayerManager.h b/Server/mods/deathmatch/logic/CPlayerManager.h index bd503380f4..0380c4bce4 100644 --- a/Server/mods/deathmatch/logic/CPlayerManager.h +++ b/Server/mods/deathmatch/logic/CPlayerManager.h @@ -40,6 +40,7 @@ class CPlayerManager CPlayer* Get(const NetServerPlayerID& PlayerSocket); CPlayer* Get(const char* szNick, bool bCaseSensitive = false); + CPlayer* GetBySerial(const std::string_view serial) const noexcept; std::list::const_iterator IterBegin() { return m_Players.begin(); }; std::list::const_iterator IterEnd() { return m_Players.end(); }; diff --git a/Server/mods/deathmatch/logic/CResource.cpp b/Server/mods/deathmatch/logic/CResource.cpp index d1b985fcfe..279f1937a7 100644 --- a/Server/mods/deathmatch/logic/CResource.cpp +++ b/Server/mods/deathmatch/logic/CResource.cpp @@ -35,7 +35,6 @@ #include #include #include -#include "version.h" #include "CStaticFunctionDefinitions.h" #ifdef WIN32 diff --git a/Server/mods/deathmatch/logic/CResourceChecker.Data.h b/Server/mods/deathmatch/logic/CResourceChecker.Data.h index e6bdee9212..630f70fd81 100644 --- a/Server/mods/deathmatch/logic/CResourceChecker.Data.h +++ b/Server/mods/deathmatch/logic/CResourceChecker.Data.h @@ -167,8 +167,8 @@ namespace //{false, "doesPedHaveJetPack", "isPedWearingJetpack"}, // Base Encoding & Decoding - {false, "base64Encode", "encodeString"}, - {false, "base64Decode", "decodeString"}, + {true, "base64Encode", "Please manually change this to encodeString (different syntax). Refer to the wiki for details"}, + {true, "base64Decode", "Please manually change this to decodeString (different syntax). Refer to the wiki for details"}, {false, "setHelicopterRotorSpeed", "setVehicleRotorSpeed"} }; @@ -271,7 +271,7 @@ namespace {true, "setPlayerDiscordJoinParams", "See GitHub PR #2499 for more details"}, // Base Encoding & Decoding - {false, "base64Encode", "encodeString"}, - {false, "base64Decode", "decodeString"} + {true, "base64Encode", "Please manually change this to encodeString (different syntax). Refer to the wiki for details"}, + {true, "base64Decode", "Please manually change this to decodeString (different syntax). Refer to the wiki for details"} }; } // namespace diff --git a/Server/mods/deathmatch/logic/CResourceChecker.cpp b/Server/mods/deathmatch/logic/CResourceChecker.cpp index 07f433f34f..9998b089ca 100644 --- a/Server/mods/deathmatch/logic/CResourceChecker.cpp +++ b/Server/mods/deathmatch/logic/CResourceChecker.cpp @@ -367,16 +367,25 @@ void CResourceChecker::CheckMetaSourceForIssues(CXMLNode* pRootNode, const strin attributes.Delete("client"); attributes.Delete("both"); - if (!m_strReqServerVersion.empty()) + // Use "both" if client and server versions are the same + if (!m_strReqServerVersion.empty() && !m_strReqClientVersion.empty() && m_strReqServerVersion == m_strReqClientVersion) { - CXMLAttribute* pAttr = attributes.Create("server"); + CXMLAttribute* pAttr = attributes.Create("both"); pAttr->SetValue(m_strReqServerVersion); } - - if (!m_strReqClientVersion.empty()) + else { - CXMLAttribute* pAttr = attributes.Create("client"); - pAttr->SetValue(m_strReqClientVersion); + if (!m_strReqServerVersion.empty()) + { + CXMLAttribute* pAttr = attributes.Create("server"); + pAttr->SetValue(m_strReqServerVersion); + } + + if (!m_strReqClientVersion.empty()) + { + CXMLAttribute* pAttr = attributes.Create("client"); + pAttr->SetValue(m_strReqClientVersion); + } } if (pbOutHasChanged) diff --git a/Server/mods/deathmatch/logic/CResourceChecker.h b/Server/mods/deathmatch/logic/CResourceChecker.h index 50c7ec00bb..ea9e7a1be9 100644 --- a/Server/mods/deathmatch/logic/CResourceChecker.h +++ b/Server/mods/deathmatch/logic/CResourceChecker.h @@ -2,7 +2,7 @@ * * PROJECT: Multi Theft Auto v1.0 * LICENSE: See LICENSE in the top level directory - * FILE: mods/deathmatch/logic/CResourceChecker.cpp + * FILE: mods/deathmatch/logic/CResourceChecker.h * PURPOSE: Resource file content checker/validator/upgrader * * Multi Theft Auto is available from http://www.multitheftauto.com/ diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index b4d1de641f..930e814879 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -10861,6 +10861,8 @@ bool CStaticFunctionDefinitions::SendSyncIntervals(CPlayer* pPlayer) BitStream.pBitStream->Write(g_TickRateSettings.iObjectSync); BitStream.pBitStream->Write(g_TickRateSettings.iKeySyncRotation); BitStream.pBitStream->Write(g_TickRateSettings.iKeySyncAnalogMove); + BitStream.pBitStream->Write(g_TickRateSettings.iPedSyncerDistance); + BitStream.pBitStream->Write(g_TickRateSettings.iUnoccupiedVehicleSyncerDistance); if (pPlayer) pPlayer->Send(CLuaPacket(SET_SYNC_INTERVALS, *BitStream.pBitStream)); else diff --git a/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp b/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp index e62547b3fb..e2adf9a5bc 100644 --- a/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp @@ -192,6 +192,7 @@ bool CMapInfoPacket::Write(NetBitStreamInterface& BitStream) const wsProps.data3.roadsignstext = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::ROADSIGNSTEXT); wsProps.data4.extendedwatercannons = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::EXTENDEDWATERCANNONS); wsProps.data5.tunnelweatherblend = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::TUNNELWEATHERBLEND); + wsProps.data6.ignoreFireState = g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::IGNOREFIRESTATE); BitStream.Write(&wsProps); } diff --git a/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h b/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h index 82fdfbd1b0..541f9b191c 100644 --- a/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h +++ b/Server/mods/deathmatch/logic/packets/CPlayerDisconnectedPacket.h @@ -39,7 +39,8 @@ class CPlayerDisconnectedPacket final : public CPacket BAN, KICK, CUSTOM, - SHUTDOWN + SHUTDOWN, + SERIAL_DUPLICATE }; CPlayerDisconnectedPacket(const char* szReason); diff --git a/Server/mods/deathmatch/mtaserver.conf b/Server/mods/deathmatch/mtaserver.conf index 11ef497fa7..726199d548 100644 --- a/Server/mods/deathmatch/mtaserver.conf +++ b/Server/mods/deathmatch/mtaserver.conf @@ -274,6 +274,12 @@ Values: 0 - Off, 1 - Enabled. Default - 0 --> 0 + + 1 + 0 + + 1 +