From db0e0fc29e57e4384cd122e0c2215f7e49219a89 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Wed, 5 Oct 2022 00:06:38 -0400 Subject: [PATCH 1/6] SiN: Episodes compatible VGUI Screens --- sp/src/game/client/c_baseplayer.cpp | 9 ++ sp/src/game/client/c_vguiscreen.cpp | 129 ++++++++++++++++++++------ sp/src/game/client/c_vguiscreen.h | 4 + sp/src/game/server/baseentity.h | 8 ++ sp/src/game/server/hl2/hl2_player.cpp | 14 +++ sp/src/game/server/vguiscreen.cpp | 110 +++++++++++++++++++--- sp/src/game/server/vguiscreen.h | 13 +++ sp/src/game/shared/gamerules.cpp | 25 +++++ sp/src/game/shared/gamerules.h | 7 +- sp/src/game/shared/in_buttons.h | 4 + 10 files changed, 282 insertions(+), 41 deletions(-) diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index 6e068341..5a21e16e 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1133,6 +1133,9 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2 | IN_VALIDVGUIINPUT); +#ifdef MAPBASE + pCmd->buttons |= IN_VGUIMODE; +#endif // MAPBASE return; } #else @@ -1142,6 +1145,9 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); +#ifdef MAPBASE + pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; +#endif // MAPBASE return; } #endif @@ -1206,6 +1212,9 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); +#ifdef MAPBASE + pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; +#endif // MAPBASE } } diff --git a/sp/src/game/client/c_vguiscreen.cpp b/sp/src/game/client/c_vguiscreen.cpp index adf8830c..3dc9cfd9 100644 --- a/sp/src/game/client/c_vguiscreen.cpp +++ b/sp/src/game/client/c_vguiscreen.cpp @@ -38,10 +38,14 @@ extern vgui::IInputInternal *g_InputInternal; #define VGUI_SCREEN_MODE_RADIUS 80 //Precache the materials -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectVGuiScreen ) -CLIENTEFFECT_MATERIAL( "engine/writez" ) +CLIENTEFFECT_REGISTER_BEGIN(PrecacheEffectVGuiScreen) +CLIENTEFFECT_MATERIAL("engine/writez") CLIENTEFFECT_REGISTER_END() +#ifdef MAPBASE +C_EntityClassList g_VGUIScreenList; +template <> C_VGuiScreen* C_EntityClassList::m_pClassList = NULL; +#endif // MAPBASE // ----------------------------------------------------------------------------- // // This is a cache of preloaded keyvalues. @@ -102,11 +106,19 @@ C_VGuiScreen::C_VGuiScreen() m_WriteZMaterial.Init( "engine/writez", TEXTURE_GROUP_VGUI ); m_OverlayMaterial.Init( m_WriteZMaterial ); + +#ifdef MAPBASE + g_VGUIScreenList.Insert(this); +#endif // MAPBASE } C_VGuiScreen::~C_VGuiScreen() { DestroyVguiScreen(); + +#ifdef MAPBASE + g_VGUIScreenList.Remove(this); +#endif // MAPBASE } //----------------------------------------------------------------------------- @@ -416,34 +428,69 @@ void C_VGuiScreen::ClientThink( void ) int px = (int)(u * m_nPixelWidth + 0.5f); int py = (int)(v * m_nPixelHeight + 0.5f); +#ifndef MAPBASE // Generate mouse input commands if ((px != m_nOldPx) || (py != m_nOldPy)) { - g_InputInternal->InternalCursorMoved( px, py ); + g_InputInternal->InternalCursorMoved(px, py); + m_nOldPx = px; m_nOldPy = py; } if (m_nButtonPressed & IN_ATTACK) { - g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED ); + g_InputInternal->SetMouseCodeState(MOUSE_LEFT, vgui::BUTTON_PRESSED); g_InputInternal->InternalMousePressed(MOUSE_LEFT); } if (m_nButtonPressed & IN_ATTACK2) { - g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_PRESSED ); - g_InputInternal->InternalMousePressed( MOUSE_RIGHT ); + g_InputInternal->SetMouseCodeState(MOUSE_RIGHT, vgui::BUTTON_PRESSED); + g_InputInternal->InternalMousePressed(MOUSE_RIGHT); } - if ( (m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus + if ((m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus { - g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED ); - g_InputInternal->InternalMouseReleased( MOUSE_LEFT ); + g_InputInternal->SetMouseCodeState(MOUSE_LEFT, vgui::BUTTON_RELEASED); + g_InputInternal->InternalMouseReleased(MOUSE_LEFT); } if (m_nButtonReleased & IN_ATTACK2) { - g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_RELEASED ); - g_InputInternal->InternalMouseReleased( MOUSE_RIGHT ); + g_InputInternal->SetMouseCodeState(MOUSE_RIGHT, vgui::BUTTON_RELEASED); + g_InputInternal->InternalMouseReleased(MOUSE_RIGHT); } +#else + vgui::VPANEL focus = g_InputInternal->GetMouseOver(); + // Generate mouse input commands + if ((px != m_nOldPx) || (py != m_nOldPy)) + { + g_InputInternal->UpdateCursorPosInternal(px, py); + + m_nOldPx = px; + m_nOldPy = py; + + focus = pPanel->IsWithinTraverse(px, py, true); + g_InputInternal->SetMouseFocus(focus); + vgui::ivgui()->PostMessage(focus, new KeyValues("CursorMoved", "xpos", px, "ypos", py), NULL); + } + + for (int i = 0; i < 2; i++) + { + const int nBit = i ? IN_ATTACK2 : (IN_ATTACK | IN_USE); + const vgui::MouseCode nButton = i ? MOUSE_RIGHT : MOUSE_LEFT; + + if ((m_nButtonReleased & nBit) || m_bLoseThinkNextFrame) // for a button release on loosing focus + { + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_PRESSED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MousePressed", "code", nButton), NULL); + } + else if (m_nButtonPressed & nBit) + { + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); + } + } +#endif // !MAPBASE + if ( m_bLoseThinkNextFrame == true ) { @@ -627,6 +674,7 @@ bool C_VGuiScreen::IsInputOnlyToOwner( void ) return (m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) != 0; } +#ifndef MAPBASE //----------------------------------------------------------------------------- // // Enumator class for finding vgui screens close to the local player @@ -634,29 +682,29 @@ bool C_VGuiScreen::IsInputOnlyToOwner( void ) //----------------------------------------------------------------------------- class CVGuiScreenEnumerator : public IPartitionEnumerator { - DECLARE_CLASS_GAMEROOT( CVGuiScreenEnumerator, IPartitionEnumerator ); + DECLARE_CLASS_GAMEROOT(CVGuiScreenEnumerator, IPartitionEnumerator); public: - virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); + virtual IterationRetval_t EnumElement(IHandleEntity* pHandleEntity); int GetScreenCount(); - C_VGuiScreen *GetVGuiScreen( int index ); + C_VGuiScreen* GetVGuiScreen(int index); private: CUtlVector< CHandle< C_VGuiScreen > > m_VguiScreens; }; -IterationRetval_t CVGuiScreenEnumerator::EnumElement( IHandleEntity *pHandleEntity ) +IterationRetval_t CVGuiScreenEnumerator::EnumElement(IHandleEntity* pHandleEntity) { - C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); - if ( pEnt == NULL ) + C_BaseEntity* pEnt = ClientEntityList().GetBaseEntityFromHandle(pHandleEntity->GetRefEHandle()); + if (pEnt == NULL) return ITERATION_CONTINUE; // FIXME.. pretty expensive... - C_VGuiScreen *pScreen = dynamic_cast(pEnt); - if ( pScreen ) + C_VGuiScreen* pScreen = dynamic_cast(pEnt); + if (pScreen) { - int i = m_VguiScreens.AddToTail( ); - m_VguiScreens[i].Set( pScreen ); + int i = m_VguiScreens.AddToTail(); + m_VguiScreens[i].Set(pScreen); } return ITERATION_CONTINUE; @@ -667,10 +715,12 @@ int CVGuiScreenEnumerator::GetScreenCount() return m_VguiScreens.Count(); } -C_VGuiScreen *CVGuiScreenEnumerator::GetVGuiScreen( int index ) +C_VGuiScreen* CVGuiScreenEnumerator::GetVGuiScreen(int index) { return m_VguiScreens[index].Get(); -} +} +#endif // !MAPBASE + //----------------------------------------------------------------------------- @@ -704,18 +754,29 @@ C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &vi Ray_t lookRay; lookRay.Init( viewPosition, lookEnd ); +#ifndef MAPBASE // Look for vgui screens that are close to the player CVGuiScreenEnumerator localScreens; - partition->EnumerateElementsInSphere( PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens ); + partition->EnumerateElementsInSphere(PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens); +#endif // !MAPBASE Vector vecOut, vecViewDelta; float flBestDist = 2.0f; C_VGuiScreen *pBestScreen = NULL; +#ifndef MAPBASE for (int i = localScreens.GetScreenCount(); --i >= 0; ) +#else + for (C_VGuiScreen* pScreen = g_VGUIScreenList.m_pClassList; pScreen != NULL; pScreen = pScreen->m_pNext) +#endif // !MAPBASE { - C_VGuiScreen *pScreen = localScreens.GetVGuiScreen(i); - +#ifndef MAPBASE + C_VGuiScreen* pScreen = localScreens.GetVGuiScreen(i); +#else + // Skip if out of PVS + if (pScreen->IsDormant()) + continue; +#endif if ( pScreen->IsAttachedToViewModel() ) continue; @@ -865,11 +926,21 @@ vgui::Panel *CVGuiScreenPanel::CreateControlByName(const char *controlName) //----------------------------------------------------------------------------- // Purpose: Called when the user presses a button //----------------------------------------------------------------------------- -void CVGuiScreenPanel::OnCommand( const char *command) +void CVGuiScreenPanel::OnCommand(const char* command) { - if ( Q_stricmp( command, "vguicancel" ) ) + if (Q_stricmp(command, "vguicancel")) { - engine->ClientCmd( const_cast( command ) ); +#ifdef MAPBASE + if (m_hEntity && m_hEntity->IsServerEntity()) + { + KeyValues* pCommand = new KeyValues("EntityCommand"); + pCommand->SetInt("entindex", m_hEntity->index); + pCommand->SetString("command_data", command); + engine->ServerCmdKeyValues(pCommand); + } + else +#endif + engine->ClientCmd(const_cast(command)); } BaseClass::OnCommand(command); diff --git a/sp/src/game/client/c_vguiscreen.h b/sp/src/game/client/c_vguiscreen.h index 71780093..331fbc78 100644 --- a/sp/src/game/client/c_vguiscreen.h +++ b/sp/src/game/client/c_vguiscreen.h @@ -66,6 +66,10 @@ class C_VGuiScreen : public C_BaseEntity public: DECLARE_CLIENTCLASS(); +#ifdef MAPBASE + C_VGuiScreen* m_pNext; +#endif // MAPBASE + C_VGuiScreen(); ~C_VGuiScreen(); diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index acbffdb2..3da44bc7 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -606,6 +606,9 @@ public: void ValidateEntityConnections(); void FireNamedOutput( const char *pszOutput, variant_t variant, CBaseEntity *pActivator, CBaseEntity *pCaller, float flDelay = 0.0f ); +#ifdef MAPBASE + virtual +#endif CBaseEntityOutput *FindNamedOutput( const char *pszOutput ); #ifdef MAPBASE_VSCRIPT void ScriptFireOutput( const char *pszOutput, HSCRIPT hActivator, HSCRIPT hCaller, const char *szValue, float flDelay ); @@ -864,6 +867,11 @@ public: void SetAIWalkable( bool bBlocksLOS ); bool IsAIWalkable( void ); + +#ifdef MAPBASE + virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) {} +#endif // MAPBASE + private: int SaveDataDescBlock( ISave &save, datamap_t *dmap ); int RestoreDataDescBlock( IRestore &restore, datamap_t *dmap ); diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index cefdeeb4..b99f05b2 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -3617,6 +3617,20 @@ void CHL2_Player::UpdateWeaponPosture( void ) { m_LowerWeaponTimer.Set( .3 ); VPROF( "CHL2_Player::UpdateWeaponPosture-CheckLower" ); + +#ifdef MAPBASE + if (m_nButtons & IN_VGUIMODE) + { + //We're over a friendly, drop our weapon + if (Weapon_Lower() == false) + { + //FIXME: We couldn't lower our weapon! + } + + return; + } +#endif // MAPBASE + Vector vecAim = BaseClass::GetAutoaimVector( AUTOAIM_SCALE_DIRECT_ONLY ); const float CHECK_FRIENDLY_RANGE = 50 * 12; diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index e049da22..8163131c 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -35,21 +35,21 @@ PRECACHE_REGISTER( vgui_screen ); //----------------------------------------------------------------------------- // Save/load //----------------------------------------------------------------------------- -BEGIN_DATADESC( CVGuiScreen ) +BEGIN_DATADESC(CVGuiScreen) - DEFINE_CUSTOM_FIELD( m_nPanelName, &g_VguiScreenStringOps ), - DEFINE_FIELD( m_nAttachmentIndex, FIELD_INTEGER ), +DEFINE_CUSTOM_FIELD(m_nPanelName, &g_VguiScreenStringOps), +DEFINE_FIELD(m_nAttachmentIndex, FIELD_INTEGER), // DEFINE_FIELD( m_nOverlayMaterial, FIELD_INTEGER ), - DEFINE_FIELD( m_fScreenFlags, FIELD_INTEGER ), - DEFINE_KEYFIELD( m_flWidth, FIELD_FLOAT, "width" ), - DEFINE_KEYFIELD( m_flHeight, FIELD_FLOAT, "height" ), - DEFINE_KEYFIELD( m_strOverlayMaterial, FIELD_STRING, "overlaymaterial" ), - DEFINE_FIELD( m_hPlayerOwner, FIELD_EHANDLE ), +DEFINE_FIELD(m_fScreenFlags, FIELD_INTEGER), +DEFINE_KEYFIELD(m_flWidth, FIELD_FLOAT, "width"), +DEFINE_KEYFIELD(m_flHeight, FIELD_FLOAT, "height"), +DEFINE_KEYFIELD(m_strOverlayMaterial, FIELD_STRING, "overlaymaterial"), +DEFINE_FIELD(m_hPlayerOwner, FIELD_EHANDLE), - DEFINE_INPUTFUNC( FIELD_VOID, "SetActive", InputSetActive ), - DEFINE_INPUTFUNC( FIELD_VOID, "SetInactive", InputSetInactive ), +DEFINE_INPUTFUNC(FIELD_VOID, "SetActive", InputSetActive), +DEFINE_INPUTFUNC(FIELD_VOID, "SetInactive", InputSetInactive), -END_DATADESC() +END_DATADESC(); //----------------------------------------------------------------------------- @@ -75,6 +75,20 @@ bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue ) *s = '\0'; } +#ifdef MAPBASE + // Named command outputs + if (szKeyName[0] == '~' && szKeyName[1]) + { + const char* pszOutputName = szKeyName + 1; + int i = m_PanelOutputs.Find(pszOutputName); + if (!m_PanelOutputs.IsValidIndex(i)) + i = m_PanelOutputs.Insert(pszOutputName, new COutputEvent); + + m_PanelOutputs[i]->ParseEventAction(szValue); + return true; + } +#endif // MAPBASE + if ( FStrEq( szKeyName, "panelname" )) { SetPanelName( szValue ); @@ -158,6 +172,80 @@ void CVGuiScreen::OnRestore() BaseClass::OnRestore(); } +#ifdef MAPBASE +CVGuiScreen::~CVGuiScreen() +{ + m_PanelOutputs.PurgeAndDeleteElements(); +} + +int CVGuiScreen::Save(ISave& save) +{ + int status = BaseClass::Save(save); + if (!status) + return 0; + + const int iCount = m_PanelOutputs.Count(); + save.WriteInt(&iCount); + for (int i = 0; i < iCount; i++) + { + CBaseEntityOutput* output = m_PanelOutputs[i]; + const int nElems = output->NumberOfElements(); + save.WriteString(m_PanelOutputs.GetElementName(i)); + save.WriteInt(&nElems); + if (!output->Save(save)) + return 0; + } + + return status; +} + +int CVGuiScreen::Restore(IRestore& restore) +{ + int status = BaseClass::Restore(restore); + if (!status) + return 0; + + const int iCount = restore.ReadInt(); + m_PanelOutputs.EnsureCapacity(iCount); + for (int i = 0; i < iCount; i++) + { + char cName[MAX_KEY]; + restore.ReadString(cName, MAX_KEY, 0); + const int iIndex = m_PanelOutputs.Insert(cName, new COutputEvent); + const int nElems = restore.ReadInt(); + if (!m_PanelOutputs[iIndex]->Restore(restore, nElems)) + return 0; + } + + return status; +} + +void CVGuiScreen::HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) +{ + const int i = m_PanelOutputs.Find(pKeyValues->GetString()); + if (m_PanelOutputs.IsValidIndex(i)) + { + variant_t Val; + Val.Set(FIELD_VOID, NULL); + m_PanelOutputs[i]->FireOutput(Val, pClient, this); + } +} + +CBaseEntityOutput* CVGuiScreen::FindNamedOutput(const char* pszOutput) +{ + if (pszOutput && pszOutput[0] == '~' && pszOutput[1]) + { + const int i = m_PanelOutputs.Find(pszOutput + 1); + if (m_PanelOutputs.IsValidIndex(i)) + return m_PanelOutputs[i]; + + return NULL; + } + + return BaseClass::FindNamedOutput(pszOutput); +} +#endif // MAPBASE + void CVGuiScreen::SetAttachmentIndex( int nIndex ) { m_nAttachmentIndex = nIndex; diff --git a/sp/src/game/server/vguiscreen.h b/sp/src/game/server/vguiscreen.h index cf720916..1cb7dc7e 100644 --- a/sp/src/game/server/vguiscreen.h +++ b/sp/src/game/server/vguiscreen.h @@ -32,6 +32,15 @@ public: virtual void Activate(); virtual void OnRestore(); +#ifdef MAPBASE + ~CVGuiScreen(); + virtual int Save(ISave& save); + virtual int Restore(IRestore& restore); + + virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues); + virtual CBaseEntityOutput* FindNamedOutput(const char* pszOutput); +#endif // MAPBASE + const char *GetPanelName() const; // Sets the screen size + resolution @@ -75,6 +84,10 @@ private: CNetworkVar( int, m_fScreenFlags ); CNetworkVar( EHANDLE, m_hPlayerOwner ); +#ifdef MAPBASE + CUtlDict m_PanelOutputs; +#endif // MAPBASE + friend CVGuiScreen *CreateVGuiScreen( const char *pScreenClassname, const char *pScreenType, CBaseEntity *pAttachedTo, CBaseEntity *pOwner, int nAttachmentIndex ); }; diff --git a/sp/src/game/shared/gamerules.cpp b/sp/src/game/shared/gamerules.cpp index cb199617..face9d54 100644 --- a/sp/src/game/shared/gamerules.cpp +++ b/sp/src/game/shared/gamerules.cpp @@ -963,3 +963,28 @@ CTacticalMissionManager *CGameRules::TacticalMissionManagerFactory( void ) } #endif + +#ifdef MAPBASE +void CGameRules::ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues) +{ +#ifndef CLIENT_DLL + static int s_nEntityCommandSymbol = KeyValues::CallGetSymbolForString("EntityCommand"); + static int s_nEntIndexSymbol = KeyValues::CallGetSymbolForString("entindex"); + static int s_nCommandDataSymbol = KeyValues::CallGetSymbolForString("command_data"); + + CBasePlayer* pPlayer = (CBasePlayer*)GetContainingEntity(pEntity); + if (!pPlayer) + return; + + if (pKeyValues->GetNameSymbol() == s_nEntityCommandSymbol) + { + CBaseEntity* pEntity = CBaseEntity::Instance(pKeyValues->GetInt(s_nEntIndexSymbol)); + KeyValues* pkvCommand = pKeyValues->FindKey(s_nCommandDataSymbol); + if (pEntity && pkvCommand) + { + pEntity->HandleEntityCommand(pPlayer, pkvCommand); + } + } +#endif // GAME_DLL +} +#endif // MAPBASE diff --git a/sp/src/game/shared/gamerules.h b/sp/src/game/shared/gamerules.h index 9ae672b6..a60f2771 100644 --- a/sp/src/game/shared/gamerules.h +++ b/sp/src/game/shared/gamerules.h @@ -178,7 +178,12 @@ public: //Allow thirdperson camera. virtual bool AllowThirdPersonCamera( void ) { return false; } - virtual void ClientCommandKeyValues( edict_t *pEntity, KeyValues *pKeyValues ) {} +#ifdef MAPBASE + virtual void ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues); +#else + virtual void ClientCommandKeyValues(edict_t* pEntity, KeyValues* pKeyValues) {} +#endif // MAPBASE + // IsConnectedUserInfoChangeAllowed allows the clients to change // cvars with the FCVAR_NOT_CONNECTED rule if it returns true diff --git a/sp/src/game/shared/in_buttons.h b/sp/src/game/shared/in_buttons.h index 870961f8..74e2ca5f 100644 --- a/sp/src/game/shared/in_buttons.h +++ b/sp/src/game/shared/in_buttons.h @@ -43,6 +43,10 @@ #define IN_GRENADE2 (1 << 24) // grenade 2 #define IN_ATTACK3 (1 << 25) +#ifdef MAPBASE +#define IN_VGUIMODE (1 << 26) +#endif // MAPBASE + #ifdef VGUI_SCREEN_FIX #define IN_VALIDVGUIINPUT (1 << 23) //bitflag for vgui fix #endif From e304b1a90eb29ec47a40aa6a144acb2759b97ded Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Tue, 1 Aug 2023 17:46:29 -0400 Subject: [PATCH 2/6] Fixed C_VGuiScreen sending reversed pressed/unpressed events to the panel --- sp/src/game/client/c_vguiscreen.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sp/src/game/client/c_vguiscreen.cpp b/sp/src/game/client/c_vguiscreen.cpp index 3dc9cfd9..c2c17723 100644 --- a/sp/src/game/client/c_vguiscreen.cpp +++ b/sp/src/game/client/c_vguiscreen.cpp @@ -480,13 +480,13 @@ void C_VGuiScreen::ClientThink( void ) if ((m_nButtonReleased & nBit) || m_bLoseThinkNextFrame) // for a button release on loosing focus { - g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_PRESSED); - vgui::ivgui()->PostMessage(focus, new KeyValues("MousePressed", "code", nButton), NULL); + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); } else if (m_nButtonPressed & nBit) { - g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); - vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL); + g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_PRESSED); + vgui::ivgui()->PostMessage(focus, new KeyValues("MousePressed", "code", nButton), NULL); } } #endif // !MAPBASE From 146df3c961b0cc7c36857045792cea756a630ed7 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Wed, 2 Aug 2023 16:48:00 -0400 Subject: [PATCH 3/6] Also suppress attack3 in vgui screen mode --- sp/src/game/client/c_baseplayer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index 5a21e16e..73d593c5 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1146,7 +1146,8 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); #ifdef MAPBASE - pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; + pCmd->buttons &= ~(IN_USE | IN_ATTACK3); + pCmd->buttons |= IN_VGUIMODE; #endif // MAPBASE return; } @@ -1213,7 +1214,8 @@ void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd ) // Kill all attack inputs if we're in vgui screen mode pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2); #ifdef MAPBASE - pCmd->buttons = (pCmd->buttons & ~IN_USE) | IN_VGUIMODE; + pCmd->buttons &= ~(IN_USE | IN_ATTACK3); + pCmd->buttons |= IN_VGUIMODE; #endif // MAPBASE } } From eb46739ab57027e52674f640b4a4c6acf4480edf Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Sat, 5 Aug 2023 18:38:04 -0400 Subject: [PATCH 4/6] Fixed vgui screens potentially crashing on save --- sp/src/game/server/vguiscreen.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index 8163131c..e26e08cc 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -82,7 +82,11 @@ bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue ) const char* pszOutputName = szKeyName + 1; int i = m_PanelOutputs.Find(pszOutputName); if (!m_PanelOutputs.IsValidIndex(i)) - i = m_PanelOutputs.Insert(pszOutputName, new COutputEvent); + { + auto pMem = new COutputEvent; + V_memset(pMem, 0, sizeof(COutputEvent)); + i = m_PanelOutputs.Insert(pszOutputName, pMem); + } m_PanelOutputs[i]->ParseEventAction(szValue); return true; From 9f34a64e636e7d32b8b25ab06cf2df5de1ab5d21 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Fri, 29 Dec 2023 14:08:13 -0500 Subject: [PATCH 5/6] Vgui screens now try to pass panel commands to the entity that created them --- sp/src/game/server/baseentity.h | 4 +++- sp/src/game/server/vguiscreen.cpp | 17 ++++++++++++++++- sp/src/game/server/vguiscreen.h | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 3da44bc7..7cd4670c 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -869,7 +869,9 @@ public: bool IsAIWalkable( void ); #ifdef MAPBASE - virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) {} + // Handle a potentially complex command from a client. + // Returns true if the command was handled successfully. + virtual bool HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) { return false; } #endif // MAPBASE private: diff --git a/sp/src/game/server/vguiscreen.cpp b/sp/src/game/server/vguiscreen.cpp index e26e08cc..86795342 100644 --- a/sp/src/game/server/vguiscreen.cpp +++ b/sp/src/game/server/vguiscreen.cpp @@ -224,15 +224,30 @@ int CVGuiScreen::Restore(IRestore& restore) return status; } -void CVGuiScreen::HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) +// Handle a command from the client-side vgui panel. +bool CVGuiScreen::HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues) { +#if defined(HL2MP) // Enable this in multiplayer. + // Restrict to commands from our owning player. + if ((m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) && pClient != m_hPlayerOwner.Get()) + return false; +#endif + + // Give the owning entity a chance to handle the command. + if (GetOwnerEntity() && GetOwnerEntity()->HandleEntityCommand(pClient, pKeyValues)) + return true; + + // See if we have an output for this command. const int i = m_PanelOutputs.Find(pKeyValues->GetString()); if (m_PanelOutputs.IsValidIndex(i)) { variant_t Val; Val.Set(FIELD_VOID, NULL); m_PanelOutputs[i]->FireOutput(Val, pClient, this); + return true; } + + return false; } CBaseEntityOutput* CVGuiScreen::FindNamedOutput(const char* pszOutput) diff --git a/sp/src/game/server/vguiscreen.h b/sp/src/game/server/vguiscreen.h index 1cb7dc7e..557cacd7 100644 --- a/sp/src/game/server/vguiscreen.h +++ b/sp/src/game/server/vguiscreen.h @@ -37,7 +37,7 @@ public: virtual int Save(ISave& save); virtual int Restore(IRestore& restore); - virtual void HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues); + virtual bool HandleEntityCommand(CBasePlayer* pClient, KeyValues* pKeyValues); virtual CBaseEntityOutput* FindNamedOutput(const char* pszOutput); #endif // MAPBASE From 9e2bdaab588a1ec8e7a9c96ac4deaccd45c5fc11 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Fri, 29 Dec 2023 21:15:23 -0500 Subject: [PATCH 6/6] Fixed vgui_screens always sending a mouse released event to the panel when the vgui_screen loses focus --- sp/src/game/client/c_vguiscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/c_vguiscreen.cpp b/sp/src/game/client/c_vguiscreen.cpp index c2c17723..7695afd8 100644 --- a/sp/src/game/client/c_vguiscreen.cpp +++ b/sp/src/game/client/c_vguiscreen.cpp @@ -478,7 +478,7 @@ void C_VGuiScreen::ClientThink( void ) const int nBit = i ? IN_ATTACK2 : (IN_ATTACK | IN_USE); const vgui::MouseCode nButton = i ? MOUSE_RIGHT : MOUSE_LEFT; - if ((m_nButtonReleased & nBit) || m_bLoseThinkNextFrame) // for a button release on loosing focus + if ((m_nButtonReleased & nBit) || ((m_nButtonState & nBit) && m_bLoseThinkNextFrame)) // for a button release on loosing focus { g_InputInternal->SetMouseCodeState(nButton, vgui::BUTTON_RELEASED); vgui::ivgui()->PostMessage(focus, new KeyValues("MouseReleased", "code", nButton), NULL);