From af7eb4ca1c3f4d365ef22c75d8318a79fd8baeb8 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Mon, 24 Aug 2026 21:19:09 +0100 Subject: [PATCH 01/14] init --- game/neo/scripts/HudLayout.res | 12 ++ src/game/client/CMakeLists.txt | 2 + src/game/client/neo/ui/neo_hud_place_name.cpp | 107 ++++++++++++++++++ src/game/client/neo/ui/neo_hud_place_name.h | 35 ++++++ src/game/server/neo/neo_player.cpp | 17 +++ src/game/shared/neo/neo_gamerules.h | 1 + 6 files changed, 174 insertions(+) create mode 100644 src/game/client/neo/ui/neo_hud_place_name.cpp create mode 100644 src/game/client/neo/ui/neo_hud_place_name.h diff --git a/game/neo/scripts/HudLayout.res b/game/neo/scripts/HudLayout.res index 363158d81..d506ac5dd 100644 --- a/game/neo/scripts/HudLayout.res +++ b/game/neo/scripts/HudLayout.res @@ -1026,4 +1026,16 @@ "SmallWeaponsFont" "NHudSpectatorOverlaySmallWeapons" "DeadTexture" "vgui/hud/kill_kill" } + + neo_place_name + { + "fieldName" "neo_place_name" + "xpos" "-4" + "ypos" "4" + "wide" "f" + + "textFont" "NHudOCRSmallNoAdditive" + "textColor" "255 255 255 255" + "textXAlignment" "2" + } } diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index 317cbb87a..4e7b78456 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -1665,6 +1665,7 @@ set(UNITY_SOURCE_NEO_UI neo/ui/neo_hud_health_thermoptic_aux.cpp neo/ui/neo_hud_hint.cpp neo/ui/neo_hud_message.cpp + neo/ui/neo_hud_place_name.cpp neo/ui/neo_hud_player_ping.cpp neo/ui/neo_hud_round_state.cpp neo/ui/neo_hud_spectator_overlay.cpp @@ -1707,6 +1708,7 @@ target_sources_grouped( neo/ui/neo_hud_health_thermoptic_aux.h neo/ui/neo_hud_hint.h neo/ui/neo_hud_message.h + neo/ui/neo_hud_place_name.h neo/ui/neo_hud_player_ping.h neo/ui/neo_hud_round_state.h neo/ui/neo_hud_spectator_overlay.h diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp new file mode 100644 index 000000000..766c29818 --- /dev/null +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -0,0 +1,107 @@ +#include "neo_hud_place_name.h" + +#include "iclientmode.h" +#include +#include "c_neo_player.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +DECLARE_NAMED_HUDELEMENT(CNEOHud_PlaceName, neo_place_name); + +NEO_HUD_ELEMENT_DECLARE_FREQ_CVAR(PlaceName, 0.1) + +CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent) + : CHudElement(pElementName), Panel(parent, pElementName) +{ + SetAutoDelete(true); + m_iHideHudElementNumber = NEO_HUD_ELEMENT_PLACE_NAME; + + if (parent) { + SetParent(parent); + } + else + { + SetParent(g_pClientMode->GetViewport()); + } + + m_szPlaceName[0] = L'\0'; + + SetVisible(true); +} + +void CNEOHud_PlaceName::ApplySchemeSettings(vgui::IScheme* pScheme) +{ + BaseClass::ApplySchemeSettings(pScheme); + + const int tall = vgui::surface()->GetFontTall(textFont); + wide = GetWide(); + SetBounds(xpos, ypos, wide, tall); + + SetFgColor(COLOR_TRANSPARENT); + SetBgColor(COLOR_TRANSPARENT); +} + +enum +{ + TEXTALIGN_LEFT = 0, + TEXTALIGN_CENTER, + TEXTALIGN_RIGHT +}; +void CNEOHud_PlaceName::UpdateStateForNeoHudElementDraw() +{ + C_NEO_Player* pTargetPlayer = C_NEO_Player::GetLocalNEOPlayer(); + if (!pTargetPlayer) + { + return; + } + + if (pTargetPlayer->IsPlayerDead()) + { + if (const int observerMode = pTargetPlayer->GetObserverMode(); + observerMode == OBS_MODE_IN_EYE || observerMode == OBS_MODE_CHASE) + { + if (C_BaseEntity* pObserverTarget = pTargetPlayer->GetObserverTarget(); + pObserverTarget && pObserverTarget->IsPlayer()) + { + pTargetPlayer = static_cast(pObserverTarget); + } + } + } + + V_snwprintf(m_szPlaceName, MAX_PLACE_NAME_LENGTH, L"%hs", pTargetPlayer->GetLastKnownPlaceName()); + switch (textXAlignment) + { + case TEXTALIGN_LEFT: + default: + textXOffset = 0; + break; + case TEXTALIGN_CENTER: + case TEXTALIGN_RIGHT: + int textWidth = 0, textHeight = 0; + vgui::surface()->GetTextSize(textFont, m_szPlaceName, textWidth, textHeight); + textXOffset = textXAlignment == TEXTALIGN_CENTER ? (wide / 2) - (textWidth / 2) : wide - textWidth; + break; + } +} + +ConVar cl_neo_hud_place_name_draw("cl_neo_hud_place_name_draw", "1", FCVAR_ARCHIVE, "Draw the place name"); +void CNEOHud_PlaceName::DrawNeoHudElement() +{ + if (!ShouldDraw()) + return; + + if (!cl_neo_hud_place_name_draw.GetBool()) + return; + + vgui::surface()->DrawSetTextFont(textFont); + vgui::surface()->DrawSetTextColor(textColor); + vgui::surface()->DrawSetTextPos(textXOffset, 0); + vgui::surface()->DrawPrintText(m_szPlaceName, V_wcslen(m_szPlaceName)); +} + +void CNEOHud_PlaceName::Paint() +{ + BaseClass::Paint(); + PaintNeoElement(); +} \ No newline at end of file diff --git a/src/game/client/neo/ui/neo_hud_place_name.h b/src/game/client/neo/ui/neo_hud_place_name.h new file mode 100644 index 000000000..c361eabc3 --- /dev/null +++ b/src/game/client/neo/ui/neo_hud_place_name.h @@ -0,0 +1,35 @@ +#pragma once + +#include "neo_hud_childelement.h" +#include "hudelement.h" +#include + +class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE(CNEOHud_PlaceName, Panel); + +public: + CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent = NULL); + void ApplySchemeSettings(vgui::IScheme* pScheme) override; + virtual void Paint() override; + +protected: + virtual void UpdateStateForNeoHudElementDraw() override; + virtual void DrawNeoHudElement() override; + virtual ConVar* GetUpdateFrequencyConVar() const override; + +private: + CNEOHud_PlaceName(const CNEOHud_PlaceName&other); + + wchar_t m_szPlaceName[MAX_PLACE_NAME_LENGTH]; + int textXOffset = 0; + int wide = 0; + + CPanelAnimationVarAliasType(int, xpos, "xpos", "80", "proportional_xpos"); + CPanelAnimationVarAliasType(int, ypos, "ypos", "80", "proportional_ypos"); + + CPanelAnimationVar(vgui::HFont, textFont, "textFont", ""); + CPanelAnimationVar(Color, textColor, "textColor", "255 255 255 255"); + CPanelAnimationVar(int, textXAlignment, "textXAlignment", "0"); + CPanelAnimationVar(int, textYAlignment, "textYAlignment", "0"); +}; \ No newline at end of file diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index bfe41aaec..9d157fdad 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -41,6 +41,7 @@ #include "nav_mesh.h" #include "neo_spawn_manager.h" #include "recipientfilter.h" +#include "nav_mesh.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -1192,6 +1193,22 @@ void CNEO_Player::PreThink(void) SuperJump(); } } + + if (TheNavMesh) + { + if (const char* placeName = TheNavMesh->PlaceToName(TheNavMesh->GetPlace(GetAbsOrigin())); + placeName && placeName[0]) + { + if (Q_strcmp(m_szLastPlaceName.Get(), placeName)) + { + Q_strncpy(m_szLastPlaceName.GetForModify(), placeName, MAX_PLACE_NAME_LENGTH); + } + } + else + { + Q_strncpy(m_szLastPlaceName.GetForModify(), "", MAX_PLACE_NAME_LENGTH); + } + } } void CNEO_Player::PlayCloakSound(bool removeLocalPlayer) diff --git a/src/game/shared/neo/neo_gamerules.h b/src/game/shared/neo/neo_gamerules.h index e59b8071b..48f008ee8 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/neo_gamerules.h @@ -171,6 +171,7 @@ enum NeoHudElements : NEO_HUD_BITS_UNDERLYING_TYPE { NEO_HUD_ELEMENT_PLAYER_PING = (static_cast(1) << 15), NEO_HUD_ELEMENT_WORLDPOS_MARKER_ENT = (static_cast(1) << 16), NEO_HUD_ELEMENT_SPECTATOR_OVERLAY = (static_cast(1) << 17), + NEO_HUD_ELEMENT_PLACE_NAME = (static_cast(1) << 18), }; enum NeoSpectateEvent { From 3f9ae6f120421e6d44280e0144f41cceb20ccf76 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Tue, 25 Aug 2026 18:22:49 +0100 Subject: [PATCH 02/14] custom place names --- src/game/server/nav_area.cpp | 21 +++++ src/game/server/nav_area.h | 4 + src/game/server/nav_file.cpp | 7 ++ src/game/server/nav_mesh.cpp | 159 +++++++++++++++++++++++++++++++++++ src/game/server/nav_mesh.h | 15 ++++ 5 files changed, 206 insertions(+) diff --git a/src/game/server/nav_area.cpp b/src/game/server/nav_area.cpp index 156e2b598..3551757a3 100644 --- a/src/game/server/nav_area.cpp +++ b/src/game/server/nav_area.cpp @@ -1265,6 +1265,12 @@ bool CNavArea::SplitEdit( bool splitAlongX, float splitEdge, CNavArea **outAlpha SplitNotification notify( this, alpha, beta ); TheNavMesh->ForAllLadders( notify ); +#ifdef NEO + // If the old area had a place name, the new areas will inherit it + alpha->m_place = m_place; + beta->m_place = m_place; +#endif // NEO + // return new areas if (outAlpha) *outAlpha = alpha; @@ -4702,6 +4708,21 @@ bool CNavArea::IsBlocked( int teamID, bool ignoreNavBlockers ) const return m_isBlocked[ teamIdx ]; } +#ifdef NEO +void CNavArea::SetPlace(Place place) +{ + if (m_place == place) + return; + + if (this == TheNavMesh->GetNavAreaByID(GetID())) + { + TheNavMesh->DecrementNumPlaces(m_place); + TheNavMesh->IncrementNumPlaces(place); + } + m_place = place; +} +#endif // NEO + //-------------------------------------------------------------------------------------------------------- void CNavArea::MarkAsBlocked( int teamID, CBaseEntity *blocker, bool bGenerateEvent ) { diff --git a/src/game/server/nav_area.h b/src/game/server/nav_area.h index ee8afa5bb..69d51465f 100644 --- a/src/game/server/nav_area.h +++ b/src/game/server/nav_area.h @@ -299,7 +299,11 @@ class CNavArea : protected CNavAreaCriticalData bool HasAttributes( int bits ) const { return ( m_attributeFlags & bits ) ? true : false; } void RemoveAttributes( int bits ) { m_attributeFlags &= ( ~bits ); } +#ifdef NEO + void SetPlace( Place place ); // set place descriptor +#else void SetPlace( Place place ) { m_place = place; } // set place descriptor +#endif // NEO Place GetPlace( void ) const { return m_place; } // get place descriptor void MarkAsBlocked( int teamID, CBaseEntity *blocker, bool bGenerateEvent = true ); // An entity can force a nav area to be blocked diff --git a/src/game/server/nav_file.cpp b/src/game/server/nav_file.cpp index e2c164101..8959a3d2c 100644 --- a/src/game/server/nav_file.cpp +++ b/src/game/server/nav_file.cpp @@ -156,13 +156,20 @@ void PlaceDirectory::Load( CUtlBuffer &fileBuffer, int version ) m_directory.RemoveAll(); // read each entry +#ifdef NEO + char placeName[MAX_PLACE_NAME_LENGTH]; +#else char placeName[256]; +#endif // NEO unsigned short len; for( int i=0; iNextPlace(placeName); +#endif // NEO Place place = TheNavMesh->NameToPlace( placeName ); if (place == UNDEFINED_PLACE) { diff --git a/src/game/server/nav_mesh.cpp b/src/game/server/nav_mesh.cpp index 299bf76ff..f04b15969 100644 --- a/src/game/server/nav_mesh.cpp +++ b/src/game/server/nav_mesh.cpp @@ -69,10 +69,12 @@ CNavMesh::CNavMesh( void ) m_editMode = NORMAL; m_bQuitWhenFinished = false; m_hostThreadModeRestoreValue = 0; +#ifndef NEO m_placeCount = 0; m_placeName = NULL; LoadPlaceDatabase(); +#endif // NEO ListenForGameEvent( "round_start" ); // ListenForGameEvent( "round_start_pre_entity" ); @@ -89,11 +91,15 @@ CNavMesh::~CNavMesh() if (m_spawnName) delete [] m_spawnName; +#ifdef NEO + m_placeName.RemoveAll(); +#else // !!!!bug!!! why does this crash in linux on server exit for( unsigned int i=0; iGetPlace()); +#endif // NEO ++m_areaCount; } @@ -568,6 +582,10 @@ void CNavMesh::RemoveNavArea( CNavArea *area ) m_avoidanceObstacleAreas.FindAndRemove( area ); m_blockedAreas.FindAndRemove( area ); +#ifdef NEO + DecrementNumPlaces(area->GetPlace()); +#endif // NEO + --m_areaCount; } @@ -1100,6 +1118,7 @@ unsigned int CNavMesh::GetPlace( const Vector &pos ) const return UNDEFINED_PLACE; } +#ifndef NEO //-------------------------------------------------------------------------------------------------------------- /** * Load the place names from a file @@ -1184,6 +1203,7 @@ void CNavMesh::LoadPlaceDatabase( void ) m_placeName[i] = placeNames[i]; } } +#endif // NEO //-------------------------------------------------------------------------------------------------------------- /** @@ -1192,8 +1212,13 @@ void CNavMesh::LoadPlaceDatabase( void ) */ const char *CNavMesh::PlaceToName( Place place ) const { +#ifdef NEO + if (place >= 1 && place <= m_placeName.Count()) + return m_placeName[ (int)place - 1 ].name; +#else if (place >= 1 && place <= m_placeCount) return m_placeName[ (int)place - 1 ]; +#endif // NEO return NULL; } @@ -1206,10 +1231,17 @@ const char *CNavMesh::PlaceToName( Place place ) const */ Place CNavMesh::NameToPlace( const char *name ) const { +#ifdef NEO + for( unsigned int i=0; i UNDEFINED_PLACE && place <= m_placeName.Count()) + { + m_placeName[place-1].count++; + } +} + +void CNavMesh::DecrementNumPlaces(Place place) +{ + if (place > UNDEFINED_PLACE && place <= m_placeName.Count()) + { + m_placeName[place-1].count--; + } +} +#endif // NEO //-------------------------------------------------------------------------------------------------------------- /** @@ -1264,12 +1365,24 @@ int CNavMesh::PlaceNameAutocomplete( char const *partial, char commands[ COMMAND partial += Q_strlen( "nav_use_place " ); int partialLength = Q_strlen( partial ); +#ifdef NEO + for( unsigned int i=0; i placeNames; +#ifdef NEO + for ( i=0; iNameToPlace(args[1]); + place != UNDEFINED_PLACE) + { + Msg( "Current place set to '%s'\n", args[1] ); + TheNavMesh->SetNavPlace(place); + return; + } + + Msg( "Current place set to new place '%s'\n", args[1] ); + TheNavMesh->SetNavPlace(TheNavMesh->NextAvailablePlace(args[1])); +#else if (args.ArgC() == 1) { // no arguments = list all available places @@ -2404,6 +2547,7 @@ void CommandNavUsePlace( const CCommand &args ) TheNavMesh->SetNavPlace( place ); } } +#endif // NEO } static ConCommand nav_use_place( "nav_use_place", CommandNavUsePlace, "If used without arguments, all available Places will be listed. If a Place argument is given, the current Place is set.", FCVAR_GAMEDLL | FCVAR_CHEAT, PlaceNameAutocompleteCallback ); @@ -2422,6 +2566,20 @@ void CommandNavPlaceReplace( const CCommand &args ) else { // two arguments - replace the first place with the second +#ifdef NEO + Place oldPlace = TheNavMesh->NameToPlace(args[1]); + if (oldPlace == UNDEFINED_PLACE) + { + Msg("Old place name not found"); + return; + } + + Place newPlace = TheNavMesh->NameToPlace(args[2]); + if (newPlace == UNDEFINED_PLACE) + { + newPlace = TheNavMesh->NextAvailablePlace(args[2]); + } +#else Place oldPlace = TheNavMesh->PartialNameToPlace( args[ 1 ] ); Place newPlace = TheNavMesh->PartialNameToPlace( args[ 2 ] ); @@ -2430,6 +2588,7 @@ void CommandNavPlaceReplace( const CCommand &args ) Msg( "Ambiguous\n" ); } else +#endif // NEO { FOR_EACH_VEC( TheNavAreas, it ) { diff --git a/src/game/server/nav_mesh.h b/src/game/server/nav_mesh.h index e778b03cd..2d6c17977 100644 --- a/src/game/server/nav_mesh.h +++ b/src/game/server/nav_mesh.h @@ -342,6 +342,12 @@ class CNavMesh : public CGameEventListener Place NameToPlace( const char *name ) const; // given a place name, return a place ID or zero if no place is defined Place PartialNameToPlace( const char *name ) const; // given the first part of a place name, return a place ID or zero if no place is defined, or the partial match is ambiguous void PrintAllPlaces( void ) const; // output a list of names to the console +#ifdef NEO + Place NextPlace(const char* name); + Place NextAvailablePlace(const char* name); + void IncrementNumPlaces(Place place); + void DecrementNumPlaces(Place place); +#endif // NEO int PlaceNameAutocomplete( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); // Given a partial place name, fill in possible place names for ConCommand autocomplete bool GetGroundHeight( const Vector &pos, float *height, Vector *normal = NULL ) const; // get the Z coordinate of the topmost ground level below the given point @@ -1128,9 +1134,18 @@ class CNavMesh : public CGameEventListener //---------------------------------------------------------------------------------- // Place directory // +#ifdef NEO + struct PlaceNameAndCount + { + char name[MAX_PLACE_NAME_LENGTH]; + int count; + }; + CUtlVectorm_placeName; // master directory of place names (i.e: "places") +#else char **m_placeName; // master directory of place names (ie: "places") unsigned int m_placeCount; // number of "places" defined in placeName[] void LoadPlaceDatabase( void ); // load the place names from a file +#endif // NEO //---------------------------------------------------------------------------------- // Edit mode From 41dad182f7b1ddf195970151f4f00d1225723081 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Thu, 27 Aug 2026 14:29:06 +0100 Subject: [PATCH 03/14] wip working example PointWorldText --- game/neo/scripts/HudLayout.res | 5 +- src/game/client/neo/ui/neo_hud_place_name.cpp | 416 +++++++++++++++++- src/game/client/neo/ui/neo_hud_place_name.h | 53 ++- src/game/client/viewrender.cpp | 21 + src/game/client/viewrender.h | 3 + src/game/server/nav_area.cpp | 4 +- src/game/server/nav_mesh.cpp | 44 +- src/game/server/nav_mesh.h | 5 +- 8 files changed, 519 insertions(+), 32 deletions(-) diff --git a/game/neo/scripts/HudLayout.res b/game/neo/scripts/HudLayout.res index d506ac5dd..b5b2842d5 100644 --- a/game/neo/scripts/HudLayout.res +++ b/game/neo/scripts/HudLayout.res @@ -1030,10 +1030,9 @@ neo_place_name { "fieldName" "neo_place_name" - "xpos" "-4" - "ypos" "4" - "wide" "f" + "textXpos" "-4" + "textYpos" "4" "textFont" "NHudOCRSmallNoAdditive" "textColor" "255 255 255 255" "textXAlignment" "2" diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp index 766c29818..0b3450097 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.cpp +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -3,6 +3,7 @@ #include "iclientmode.h" #include #include "c_neo_player.h" +#include "view.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -11,9 +12,24 @@ DECLARE_NAMED_HUDELEMENT(CNEOHud_PlaceName, neo_place_name); NEO_HUD_ELEMENT_DECLARE_FREQ_CVAR(PlaceName, 0.1) +static CNEOHud_PlaceName *g_PlaceName = nullptr; + +static const char* TEXT_MATERIAL = "editor/worldtext_9"; +ConVar cl_neo_hud_place_names_depth_test("cl_neo_hud_place_names_depth_test", "0", FCVAR_ARCHIVE, "Depth test in-world nearby place names", true, 0.0f, true, 1.0f, + [](IConVar* var, const char* pOldValue, float flOldValue)->void{ + PrecacheMaterial( TEXT_MATERIAL ); + IMaterial* textMaterial = g_PlaceName->GetFont(); + if (!textMaterial) + return; + + textMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, !cl_neo_hud_place_names_depth_test.GetBool() ); +}); + CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent) : CHudElement(pElementName), Panel(parent, pElementName) { + g_PlaceName = this; + SetAutoDelete(true); m_iHideHudElementNumber = NEO_HUD_ELEMENT_PLACE_NAME; @@ -28,15 +44,26 @@ CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *pare m_szPlaceName[0] = L'\0'; SetVisible(true); + + PrecacheMaterial( TEXT_MATERIAL ); + m_Font.Init(TEXT_MATERIAL, TEXTURE_GROUP_PRECACHED, true); + + const PointWorldText foo = { "Important Place", {100, 100, 400}}; + places.AddToTail(foo); +} + +CNEOHud_PlaceName::~CNEOHud_PlaceName() +{ + g_PlaceName = nullptr; } void CNEOHud_PlaceName::ApplySchemeSettings(vgui::IScheme* pScheme) { BaseClass::ApplySchemeSettings(pScheme); - const int tall = vgui::surface()->GetFontTall(textFont); - wide = GetWide(); - SetBounds(xpos, ypos, wide, tall); + int wide = 0, tall = 0; + vgui::surface()->GetScreenSize(wide, tall); + SetBounds(0, 0, wide, tall); SetFgColor(COLOR_TRANSPARENT); SetBgColor(COLOR_TRANSPARENT); @@ -85,23 +112,390 @@ void CNEOHud_PlaceName::UpdateStateForNeoHudElementDraw() } } -ConVar cl_neo_hud_place_name_draw("cl_neo_hud_place_name_draw", "1", FCVAR_ARCHIVE, "Draw the place name"); +ConVar cl_neo_hud_curent_place_name_draw("cl_neo_hud_curent_place_name_draw", "1", FCVAR_ARCHIVE, "Draw the current place name", true, 0.0f, true, 1.0f); + +static bool bShouldDrawPlaceNames = false; +static ConCommand startshowplacenames("+showplacenames", [](const CCommand& args)->void {bShouldDrawPlaceNames = true; }); +static ConCommand endshowplacenames("-showplacenames", [](const CCommand& args)->void {bShouldDrawPlaceNames = false; }); + +static float placeNamesRadiusSquared = 0.0f; +ConVar cl_neo_hud_place_names_radius("cl_neo_hud_place_names_radius", "2048", FCVAR_ARCHIVE, "Radius from the camera within which to draw the names of all nearby places", true, 0.0f, false, 0.0f, + [](IConVar* var, const char* pOldValue, float flOldValue)->void{ + placeNamesRadiusSquared = pow(cl_neo_hud_place_names_radius.GetFloat(), 2); +}); + void CNEOHud_PlaceName::DrawNeoHudElement() { if (!ShouldDraw()) return; - if (!cl_neo_hud_place_name_draw.GetBool()) - return; - - vgui::surface()->DrawSetTextFont(textFont); - vgui::surface()->DrawSetTextColor(textColor); - vgui::surface()->DrawSetTextPos(textXOffset, 0); - vgui::surface()->DrawPrintText(m_szPlaceName, V_wcslen(m_szPlaceName)); + if (cl_neo_hud_curent_place_name_draw.GetBool()) + { + vgui::surface()->DrawSetTextFont(textFont); + vgui::surface()->DrawSetTextColor(textColor); + vgui::surface()->DrawSetTextPos(textXOffset, 0); + vgui::surface()->DrawPrintText(m_szPlaceName, V_wcslen(m_szPlaceName)); + } } void CNEOHud_PlaceName::Paint() { BaseClass::Paint(); PaintNeoElement(); +} + +static float flPlaceNameOpacity = 0.f; +void CNEOHud_PlaceName::DrawPlaceNames() +{ + constexpr int ANIMATION_SPEED = 2; + if (bShouldDrawPlaceNames) + { + flPlaceNameOpacity = min(1.0f, flPlaceNameOpacity + (gpGlobals->frametime * ANIMATION_SPEED)); + } + else + { + flPlaceNameOpacity = max(0.0f, flPlaceNameOpacity - (gpGlobals->frametime * ANIMATION_SPEED)); + } + if (flPlaceNameOpacity) + { + for (PointWorldText place : places) + { + place.DrawModel(); + } + } +} + +CNEOHud_PlaceName* GetPlaceName() +{ + return g_PlaceName; +} + +typedef struct Character { + int codePoint, x, y, width, height, originX, originY, advance; +} Character; + +typedef struct Font { + const char *name; + int size, bold, italic, width, height, characterCount; + Character *characters; +} Font; + +static Character characters_Roboto_Mono[] = { + {' ', 167, 352, 12, 12, 6, 6, 77}, + {'!', 675, 144, 27, 104, -24, 97, 77}, + {'"', 1859, 249, 44, 42, -16, 102, 77}, + {'#', 702, 144, 82, 103, 2, 97, 77}, + {'$', 324, 0, 70, 131, -4, 112, 77}, + {'%', 1322, 0, 83, 106, 3, 98, 77}, + {'&', 1405, 0, 80, 106, -1, 98, 77}, + {'\'', 1903, 249, 22, 42, -25, 102, 77}, + {'(', 0, 0, 45, 144, -16, 109, 77}, + {')', 45, 0, 45, 144, -14, 109, 77}, + {'*', 1497, 249, 72, 73, -4, 97, 77}, + {'+', 1422, 249, 75, 78, -1, 81, 77}, + {',', 1829, 249, 30, 47, -16, 20, 77}, + {'-', 37, 352, 60, 22, -8, 51, 77}, + {'.', 2008, 249, 30, 30, -25, 22, 77}, + {'/', 568, 0, 60, 111, -10, 97, 77}, + {'0', 1788, 0, 71, 106, -3, 98, 77}, + {'1', 342, 249, 47, 103, -7, 97, 77}, + {'2', 0, 144, 74, 105, 1, 98, 77}, + {'3', 1859, 0, 70, 106, 0, 98, 77}, + {'4', 1263, 144, 78, 103, 1, 97, 77}, + {'5', 572, 144, 69, 104, -6, 97, 77}, + {'6', 74, 144, 70, 105, -3, 97, 77}, + {'7', 1491, 144, 73, 103, -1, 97, 77}, + {'8', 1929, 0, 70, 106, -5, 98, 77}, + {'9', 144, 144, 70, 105, -3, 98, 77}, + {':', 459, 249, 30, 85, -28, 77, 77}, + {';', 641, 144, 34, 104, -24, 77, 77}, + {'<', 1636, 249, 65, 69, -5, 75, 77}, + {'=', 1761, 249, 68, 48, -5, 65, 77}, + {'>', 1569, 249, 67, 69, -5, 75, 77}, + {'?', 283, 144, 66, 105, -6, 98, 77}, + {'@', 349, 144, 80, 104, 2, 97, 77}, + {'A', 865, 144, 80, 103, 1, 97, 77}, + {'B', 1852, 144, 71, 103, -5, 97, 77}, + {'C', 1713, 0, 75, 106, -1, 98, 77}, + {'D', 1417, 144, 74, 103, -4, 97, 77}, + {'E', 71, 249, 68, 103, -5, 97, 77}, + {'F', 139, 249, 68, 103, -6, 97, 77}, + {'G', 1485, 0, 76, 106, 0, 98, 77}, + {'H', 1923, 144, 71, 103, -3, 97, 77}, + {'I', 275, 249, 67, 103, -5, 97, 77}, + {'J', 501, 144, 71, 104, 0, 97, 77}, + {'K', 1341, 144, 76, 103, -5, 97, 77}, + {'L', 207, 249, 68, 103, -6, 97, 77}, + {'M', 1564, 144, 72, 103, -3, 97, 77}, + {'N', 0, 249, 71, 103, -3, 97, 77}, + {'O', 1561, 0, 76, 106, -1, 98, 77}, + {'P', 1636, 144, 72, 103, -6, 97, 77}, + {'Q', 416, 0, 79, 120, 0, 98, 77}, + {'R', 1708, 144, 72, 103, -5, 97, 77}, + {'S', 1637, 0, 76, 106, -1, 98, 77}, + {'T', 945, 144, 80, 103, 1, 97, 77}, + {'U', 429, 144, 72, 104, -3, 97, 77}, + {'V', 1105, 144, 79, 103, 1, 97, 77}, + {'W', 784, 144, 81, 103, 1, 97, 77}, + {'X', 1184, 144, 79, 103, 0, 97, 77}, + {'Y', 1025, 144, 80, 103, 2, 97, 77}, + {'Z', 1780, 144, 72, 103, -1, 97, 77}, + {'[', 90, 0, 37, 136, -21, 110, 77}, + {'\\', 628, 0, 60, 111, -9, 97, 77}, + {']', 127, 0, 37, 136, -19, 110, 77}, + {'^', 1701, 249, 60, 61, -9, 97, 77}, + {'_', 97, 352, 70, 21, -4, 6, 77}, + {'`', 0, 352, 37, 29, -20, 99, 77}, + {'a', 706, 249, 70, 82, -4, 75, 77}, + {'b', 688, 0, 70, 109, -5, 102, 77}, + {'c', 635, 249, 71, 82, -3, 75, 77}, + {'d', 758, 0, 69, 109, -3, 102, 77}, + {'e', 563, 249, 72, 82, -2, 75, 77}, + {'f', 495, 0, 73, 111, -4, 105, 77}, + {'g', 898, 0, 69, 108, -3, 75, 77}, + {'h', 1036, 0, 68, 108, -5, 102, 77}, + {'i', 214, 144, 69, 105, -7, 98, 77}, + {'j', 272, 0, 52, 132, -7, 98, 77}, + {'k', 827, 0, 71, 108, -5, 102, 77}, + {'l', 967, 0, 69, 108, -7, 102, 77}, + {'m', 845, 249, 78, 81, 0, 75, 77}, + {'n', 923, 249, 68, 81, -5, 75, 77}, + {'o', 489, 249, 74, 82, -2, 75, 77}, + {'p', 1184, 0, 69, 107, -5, 75, 77}, + {'q', 1253, 0, 69, 107, -3, 75, 77}, + {'r', 1058, 249, 59, 81, -15, 75, 77}, + {'s', 776, 249, 69, 82, -5, 75, 77}, + {'t', 389, 249, 70, 97, -3, 90, 77}, + {'u', 991, 249, 67, 81, -5, 74, 77}, + {'v', 1200, 249, 76, 80, 0, 74, 77}, + {'w', 1117, 249, 83, 80, 3, 74, 77}, + {'x', 1276, 249, 76, 80, -1, 74, 77}, + {'y', 1104, 0, 80, 107, 2, 74, 77}, + {'z', 1352, 249, 70, 80, -4, 74, 77}, + {'{', 164, 0, 54, 135, -14, 106, 77}, + {'|', 394, 0, 22, 128, -28, 97, 77}, + {'}', 218, 0, 54, 135, -14, 106, 77}, + {'~', 1925, 249, 83, 37, 3, 56, 77}, +}; + +static Font font_Roboto_Mono = {"Roboto Mono", 128, 0, 0, 2048, 512, 95, characters_Roboto_Mono}; + +PointWorldText::PointWorldText() +{ + PrecacheMaterial( TEXT_MATERIAL ); + + V_memset(m_szText, 0, sizeof(m_szText)); +} + +PointWorldText::PointWorldText(const char* pszText, Vector pos) +{ + PrecacheMaterial( TEXT_MATERIAL ); + + SetText(pszText); + m_vecAbsOrigin = pos; +} + +PointWorldText::~PointWorldText() +{ +} + +void PointWorldText::SetText( const char* pszText ) +{ + m_nTextLength = V_strlen( pszText ); + V_strncpy( m_szText, pszText, sizeof(m_szText) ); + UpdateTextWorldSize(); +} + +void PointWorldText::UpdateTextWorldSize() +{ + CalcTextTotalSize( m_flTextWorldWidth, m_flTextWorldHeight ); +} +void PointWorldText::CalcTextTotalSize(float &outWidth, float &outHeight) +{ + outWidth = 0.0f; + outHeight = 0.0f; + + const char *szText = m_szText; + if ( !szText[0] ) + return; + + int nNumChars = m_nTextLength; + if ( !nNumChars ) + return; + + float screenSize = m_flTextSize; + float screenSpacingX = GetTextSpacingX(); + float screenSpacingY = GetTextSpacingY(); + Font* font = &font_Roboto_Mono; + outHeight += font->size; + float flLineWidth = 0.0f; + for ( int i = 0; i < nNumChars; i++ ) + { + char nChar = *(szText++); + unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); + Character *character = &font->characters[ nCharIdx ]; + float scale = screenSize / (float)font->size; + if ( nChar == '\n' ) + { + outWidth = Max( outWidth, flLineWidth ); + flLineWidth = 0.0f; + outHeight += (font->size + screenSpacingY) * scale; + continue; + } + flLineWidth += (character->advance + screenSpacingX) * scale; + } + outWidth = Max( outWidth, flLineWidth ); +} + +float PointWorldText::GetTextWorldWidth() const +{ + return m_flTextWorldWidth; +} +float PointWorldText::GetTextWorldHeight() const +{ + return m_flTextWorldHeight; +} +float PointWorldText::GetTextSpacingX() const +{ + return m_flTextSpacingX; +} +float PointWorldText::GetTextSpacingY() const +{ + return m_flTextSpacingY; +} + +int PointWorldText::DrawModel( ) +{ + const char *szText = m_szText; + if ( !szText[0] ) + return 0; + + int nNumChars = m_nTextLength; + if ( !nNumChars ) + return 0; + + if (!g_PlaceName) + return 0; + + IMaterial* pDebugText = g_PlaceName->GetFont(); + if ( !pDebugText ) + return 0; + + Vector ViewForward( 1.0f, 0.0f, 0.0f ); + Vector ViewUp( 0.0f, 1.0f, 0.0f ); + Vector ViewRight( 0.0f, 0.0f, -1.0f ); + Vector vecStartPos; + VectorCopy( GetAbsOrigin(), vecStartPos ); + + float screenSize = m_flTextSize; + float screenSpacingX = GetTextSpacingX(); + float screenSpacingY = GetTextSpacingY(); + + switch ( m_nOrientation ) + { + // always orient towards screen + case 1: + ViewForward = -CurrentViewForward(); + ViewUp = CurrentViewUp(); + ViewRight = CurrentViewRight(); + // center the text for nicer rotation + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; + // orient towards screen but align with Z axis + case 2: + ViewForward = -CurrentViewForward(); + ViewUp = Vector(0, 0, 1); + ViewRight = CurrentViewRight(); + // center the text for nicer rotation + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; + // entity orientation + default: + AngleVectors( GetAbsAngles(), &ViewForward, &ViewRight, &ViewUp ); + break; + } + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( pDebugText ); + pDebugText->IncrementReferenceCount(); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, nNumChars ); + + Vector vecOrigStartPos = vecStartPos; + + Font *font = &font_Roboto_Mono; + + color32 color = m_colTextColor; + color.a *= flPlaceNameOpacity; + const float distanceSquared = MainViewOrigin().DistToSqr(GetAbsOrigin()); + if (distanceSquared > placeNamesRadiusSquared) + { + color.a *= 1.f - min(1.f, ((distanceSquared - placeNamesRadiusSquared) / placeNamesRadiusSquared)); + } + byte* pColor = (byte*)&color; + + for ( int i = 0; i < nNumChars; i++ ) + { + char nChar = *(szText++); + unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); + Character *character = &font->characters[ nCharIdx ]; + float scale = screenSize / (float)font->size; + if ( nChar == '\n' ) + { + vecOrigStartPos -= ( ViewUp * ( (font->size + screenSpacingY) * scale ) ); + vecStartPos = vecOrigStartPos; + continue; + } + if ( nChar != ' ' ) + { + float x, y, s, t; + + x = -character->originX; + y = -character->originY; + s = character->x / (float)font->width; + t = character->y / (float)font->height; + Vector v0 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v0.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX; + y = -character->originY + character->height; + s = character->x / (float)font->width; + t = (character->y + character->height) / (float)font->height; + Vector v2 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v2.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX + character->width; + y = -character->originY + character->height; + s = (character->x + character->width) / (float)font->width; + t = (character->y + character->height) / (float)font->height; + Vector v3 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v3.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX + character->width; + y = -character->originY; + s = (character->x + character->width) / (float)font->width; + t = (character->y) / (float)font->height; + Vector v1 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v1.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + } + vecStartPos += ViewRight * ((character->advance + screenSpacingX) * scale); + } + meshBuilder.End(); + pMesh->Draw(); + return 1; } \ No newline at end of file diff --git a/src/game/client/neo/ui/neo_hud_place_name.h b/src/game/client/neo/ui/neo_hud_place_name.h index c361eabc3..558c5059c 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.h +++ b/src/game/client/neo/ui/neo_hud_place_name.h @@ -4,14 +4,56 @@ #include "hudelement.h" #include +class PointWorldText +{ +public: + PointWorldText(); + PointWorldText(const char* pszText, Vector pos); + ~PointWorldText(); + + int DrawModel(); + + void SetText(const char* pszText); + void SetFont(int nFont); + + Vector GetAbsOrigin() { return m_vecAbsOrigin; } + QAngle GetAbsAngles() { return m_vecAbsAngles; } + +private: + void CalcTextTotalSize(float &outWidth, float &outHeight); + void UpdateTextWorldSize(); + + float GetTextWorldWidth() const; + float GetTextWorldHeight() const; + float GetTextSpacingX() const; + float GetTextSpacingY() const; + + Vector m_vecAbsOrigin = {0, 0, 0}; + QAngle m_vecAbsAngles = {0, 0, 0}; + + char m_szText[ MAX_PLACE_NAME_LENGTH ]; + float m_flTextSize = 100.f; + float m_flTextSpacingX = 0.f; + float m_flTextSpacingY = 0.f; + color32 m_colTextColor = {255, 255, 255, 255}; + int m_nOrientation = 2; + int m_nTextLength = 0; + + float m_flTextWorldWidth = 0.f; + float m_flTextWorldHeight = 0.f; +}; + class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, public vgui::Panel { DECLARE_CLASS_SIMPLE(CNEOHud_PlaceName, Panel); public: CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent = NULL); + ~CNEOHud_PlaceName(); void ApplySchemeSettings(vgui::IScheme* pScheme) override; virtual void Paint() override; + void DrawPlaceNames(); + CMaterialReference GetFont() const { return m_Font; }; protected: virtual void UpdateStateForNeoHudElementDraw() override; @@ -25,11 +67,14 @@ class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, publi int textXOffset = 0; int wide = 0; - CPanelAnimationVarAliasType(int, xpos, "xpos", "80", "proportional_xpos"); - CPanelAnimationVarAliasType(int, ypos, "ypos", "80", "proportional_ypos"); + CUtlVector places; + CMaterialReference m_Font; + CPanelAnimationVarAliasType(int, textXpos, "textXpos", "80", "proportional_xpos"); + CPanelAnimationVarAliasType(int, textYpos, "textYpos", "80", "proportional_ypos"); CPanelAnimationVar(vgui::HFont, textFont, "textFont", ""); CPanelAnimationVar(Color, textColor, "textColor", "255 255 255 255"); CPanelAnimationVar(int, textXAlignment, "textXAlignment", "0"); - CPanelAnimationVar(int, textYAlignment, "textYAlignment", "0"); -}; \ No newline at end of file +}; + +CNEOHud_PlaceName* GetPlaceName(); \ No newline at end of file diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index 19b69e065..82b57f4cc 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -68,6 +68,7 @@ #ifdef NEO #include "neo_player_shared.h" #include +#include "ui/neo_hud_place_name.h" #endif // NEO #include "rendertexture.h" #include "viewpostprocess.h" @@ -2000,6 +2001,22 @@ void CViewRender::RenderPlayerSprites() GetClientVoiceMgr()->DrawHeadLabels(); } +#ifdef NEO +//----------------------------------------------------------------------------- +// Purpose: Renders voice feedback and other sprites attached to players +// Input : none +//----------------------------------------------------------------------------- +void CViewRender::RenderPlaceNames() +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + if (auto placeNameHudElement = GetPlaceName()) + { + placeNameHudElement->DrawPlaceNames(); + } +} +#endif // NEO + //----------------------------------------------------------------------------- // Sets up, cleans up the main 3D view //----------------------------------------------------------------------------- @@ -2240,6 +2257,10 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int RenderPlayerSprites(); +#ifdef NEO + RenderPlaceNames(); +#endif // NEO + // Image-space motion blur if ( !building_cubemaps.GetBool() && viewRender.m_bDoBloomAndToneMapping ) // We probably should use a different view. variable here { diff --git a/src/game/client/viewrender.h b/src/game/client/viewrender.h index 6e6234986..5199f4508 100644 --- a/src/game/client/viewrender.h +++ b/src/game/client/viewrender.h @@ -362,6 +362,9 @@ class CViewRender : public IViewRender, virtual void Render( vrect_t *rect ); virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ); virtual void RenderPlayerSprites(); +#ifdef NEO + virtual void RenderPlaceNames(); +#endif // NEO virtual void Render2DEffectsPreHUD( const CViewSetup &view ); virtual void Render2DEffectsPostHUD( const CViewSetup &view ); diff --git a/src/game/server/nav_area.cpp b/src/game/server/nav_area.cpp index 3551757a3..4050b9f79 100644 --- a/src/game/server/nav_area.cpp +++ b/src/game/server/nav_area.cpp @@ -4716,8 +4716,8 @@ void CNavArea::SetPlace(Place place) if (this == TheNavMesh->GetNavAreaByID(GetID())) { - TheNavMesh->DecrementNumPlaces(m_place); - TheNavMesh->IncrementNumPlaces(place); + TheNavMesh->DecrementNumPlaces(m_place, this); + TheNavMesh->IncrementNumPlaces(place, this); } m_place = place; } diff --git a/src/game/server/nav_mesh.cpp b/src/game/server/nav_mesh.cpp index f04b15969..4dd8d99ca 100644 --- a/src/game/server/nav_mesh.cpp +++ b/src/game/server/nav_mesh.cpp @@ -525,7 +525,7 @@ void CNavMesh::AddNavArea( CNavArea *area ) } #ifdef NEO - IncrementNumPlaces(area->GetPlace()); + IncrementNumPlaces(area->GetPlace(), area); #endif // NEO ++m_areaCount; @@ -583,7 +583,7 @@ void CNavMesh::RemoveNavArea( CNavArea *area ) m_blockedAreas.FindAndRemove( area ); #ifdef NEO - DecrementNumPlaces(area->GetPlace()); + DecrementNumPlaces(area->GetPlace(), area); #endif // NEO --m_areaCount; @@ -1312,7 +1312,7 @@ Place CNavMesh::PartialNameToPlace( const char *name ) const */ Place CNavMesh::NextPlace(const char* name) { - auto placeNameAndCount = PlaceNameAndCount("", 0); + PlaceNameAndCount placeNameAndCount = { "", 0 }; V_strcpy_safe(placeNameAndCount.name, name); return m_placeName.AddToTail(placeNameAndCount) + 1; } @@ -1333,25 +1333,49 @@ Place CNavMesh::NextAvailablePlace(const char* name) } } - auto placeNameAndCount = PlaceNameAndCount("", 0); + PlaceNameAndCount placeNameAndCount = { "", 0 }; V_strcpy_safe(placeNameAndCount.name, name); return m_placeName.AddToTail(placeNameAndCount) + 1; } -void CNavMesh::IncrementNumPlaces(Place place) +void CNavMesh::IncrementNumPlaces(Place place, CNavArea* area) { - if (place > UNDEFINED_PLACE && place <= m_placeName.Count()) + if (place <= UNDEFINED_PLACE || place > m_placeName.Count()) { - m_placeName[place-1].count++; + return; + } + + const int i = place - 1; + const int newCount = m_placeName[i].count + 1; + if (newCount != 0) + { + m_placeName[i].averageCenter = ((m_placeName[i].averageCenter * m_placeName[i].count) + area->GetCenter()) / newCount; + } + else + { + m_placeName[i].averageCenter = vec3_origin; } + m_placeName[i].count = newCount; } -void CNavMesh::DecrementNumPlaces(Place place) +void CNavMesh::DecrementNumPlaces(Place place, CNavArea* area) { - if (place > UNDEFINED_PLACE && place <= m_placeName.Count()) + if (place <= UNDEFINED_PLACE || place > m_placeName.Count()) + { + return; + } + + const int i = place - 1; + const int newCount = m_placeName[i].count - 1; + if (newCount != 0) + { + m_placeName[i].averageCenter = ((m_placeName[i].averageCenter * m_placeName[i].count) - area->GetCenter()) / newCount; + } + else { - m_placeName[place-1].count--; + m_placeName[i].averageCenter = vec3_origin; } + m_placeName[i].count = newCount; } #endif // NEO diff --git a/src/game/server/nav_mesh.h b/src/game/server/nav_mesh.h index 2d6c17977..090d336e5 100644 --- a/src/game/server/nav_mesh.h +++ b/src/game/server/nav_mesh.h @@ -345,8 +345,8 @@ class CNavMesh : public CGameEventListener #ifdef NEO Place NextPlace(const char* name); Place NextAvailablePlace(const char* name); - void IncrementNumPlaces(Place place); - void DecrementNumPlaces(Place place); + void IncrementNumPlaces(Place place, CNavArea* area); + void DecrementNumPlaces(Place place, CNavArea* area); #endif // NEO int PlaceNameAutocomplete( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); // Given a partial place name, fill in possible place names for ConCommand autocomplete @@ -1139,6 +1139,7 @@ class CNavMesh : public CGameEventListener { char name[MAX_PLACE_NAME_LENGTH]; int count; + Vector averageCenter; }; CUtlVectorm_placeName; // master directory of place names (i.e: "places") #else From b77218457c2094a3636fac47d6008cfb59ead372 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Thu, 27 Aug 2026 15:00:37 +0100 Subject: [PATCH 04/14] move neopointworldtext to new file --- src/game/client/CMakeLists.txt | 2 + .../client/neo/c_neo_point_world_text.cpp | 322 +++++++++++++++ src/game/client/neo/c_neo_point_world_text.h | 43 ++ src/game/client/neo/ui/neo_hud_place_name.cpp | 375 ++---------------- src/game/client/neo/ui/neo_hud_place_name.h | 40 +- 5 files changed, 396 insertions(+), 386 deletions(-) create mode 100644 src/game/client/neo/c_neo_point_world_text.cpp create mode 100644 src/game/client/neo/c_neo_point_world_text.h diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index 4e7b78456..f8c0a6dfb 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -1571,6 +1571,7 @@ target_sources_grouped( set(UNITY_SOURCE_NEO_SRC_CLIENT neo/c_neo_message.cpp neo/c_neo_npc_dummy.cpp + neo/c_neo_point_world_text.cpp neo/c_neo_player.cpp neo/c_neo_te_tocflash.cpp neo/neo_fixup_glshaders.cpp @@ -1589,6 +1590,7 @@ target_sources_grouped( FILES neo/c_neo_message.h neo/c_neo_npc_dummy.h + neo/c_neo_point_world_text.h neo/c_neo_player.h neo/c_neo_te_tocflash.h neo/neo_fixup_glshaders.h diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp new file mode 100644 index 000000000..9294ada12 --- /dev/null +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -0,0 +1,322 @@ +#include "c_neo_point_world_text.h" +#include "view.h" + +typedef struct Character { + int codePoint, x, y, width, height, originX, originY, advance; +} Character; + +typedef struct Font { + const char *name; + int size, bold, italic, width, height, characterCount; + Character *characters; +} Font; + +static Character characters_Roboto_Mono[] = { + {' ', 167, 352, 12, 12, 6, 6, 77}, + {'!', 675, 144, 27, 104, -24, 97, 77}, + {'"', 1859, 249, 44, 42, -16, 102, 77}, + {'#', 702, 144, 82, 103, 2, 97, 77}, + {'$', 324, 0, 70, 131, -4, 112, 77}, + {'%', 1322, 0, 83, 106, 3, 98, 77}, + {'&', 1405, 0, 80, 106, -1, 98, 77}, + {'\'', 1903, 249, 22, 42, -25, 102, 77}, + {'(', 0, 0, 45, 144, -16, 109, 77}, + {')', 45, 0, 45, 144, -14, 109, 77}, + {'*', 1497, 249, 72, 73, -4, 97, 77}, + {'+', 1422, 249, 75, 78, -1, 81, 77}, + {',', 1829, 249, 30, 47, -16, 20, 77}, + {'-', 37, 352, 60, 22, -8, 51, 77}, + {'.', 2008, 249, 30, 30, -25, 22, 77}, + {'/', 568, 0, 60, 111, -10, 97, 77}, + {'0', 1788, 0, 71, 106, -3, 98, 77}, + {'1', 342, 249, 47, 103, -7, 97, 77}, + {'2', 0, 144, 74, 105, 1, 98, 77}, + {'3', 1859, 0, 70, 106, 0, 98, 77}, + {'4', 1263, 144, 78, 103, 1, 97, 77}, + {'5', 572, 144, 69, 104, -6, 97, 77}, + {'6', 74, 144, 70, 105, -3, 97, 77}, + {'7', 1491, 144, 73, 103, -1, 97, 77}, + {'8', 1929, 0, 70, 106, -5, 98, 77}, + {'9', 144, 144, 70, 105, -3, 98, 77}, + {':', 459, 249, 30, 85, -28, 77, 77}, + {';', 641, 144, 34, 104, -24, 77, 77}, + {'<', 1636, 249, 65, 69, -5, 75, 77}, + {'=', 1761, 249, 68, 48, -5, 65, 77}, + {'>', 1569, 249, 67, 69, -5, 75, 77}, + {'?', 283, 144, 66, 105, -6, 98, 77}, + {'@', 349, 144, 80, 104, 2, 97, 77}, + {'A', 865, 144, 80, 103, 1, 97, 77}, + {'B', 1852, 144, 71, 103, -5, 97, 77}, + {'C', 1713, 0, 75, 106, -1, 98, 77}, + {'D', 1417, 144, 74, 103, -4, 97, 77}, + {'E', 71, 249, 68, 103, -5, 97, 77}, + {'F', 139, 249, 68, 103, -6, 97, 77}, + {'G', 1485, 0, 76, 106, 0, 98, 77}, + {'H', 1923, 144, 71, 103, -3, 97, 77}, + {'I', 275, 249, 67, 103, -5, 97, 77}, + {'J', 501, 144, 71, 104, 0, 97, 77}, + {'K', 1341, 144, 76, 103, -5, 97, 77}, + {'L', 207, 249, 68, 103, -6, 97, 77}, + {'M', 1564, 144, 72, 103, -3, 97, 77}, + {'N', 0, 249, 71, 103, -3, 97, 77}, + {'O', 1561, 0, 76, 106, -1, 98, 77}, + {'P', 1636, 144, 72, 103, -6, 97, 77}, + {'Q', 416, 0, 79, 120, 0, 98, 77}, + {'R', 1708, 144, 72, 103, -5, 97, 77}, + {'S', 1637, 0, 76, 106, -1, 98, 77}, + {'T', 945, 144, 80, 103, 1, 97, 77}, + {'U', 429, 144, 72, 104, -3, 97, 77}, + {'V', 1105, 144, 79, 103, 1, 97, 77}, + {'W', 784, 144, 81, 103, 1, 97, 77}, + {'X', 1184, 144, 79, 103, 0, 97, 77}, + {'Y', 1025, 144, 80, 103, 2, 97, 77}, + {'Z', 1780, 144, 72, 103, -1, 97, 77}, + {'[', 90, 0, 37, 136, -21, 110, 77}, + {'\\', 628, 0, 60, 111, -9, 97, 77}, + {']', 127, 0, 37, 136, -19, 110, 77}, + {'^', 1701, 249, 60, 61, -9, 97, 77}, + {'_', 97, 352, 70, 21, -4, 6, 77}, + {'`', 0, 352, 37, 29, -20, 99, 77}, + {'a', 706, 249, 70, 82, -4, 75, 77}, + {'b', 688, 0, 70, 109, -5, 102, 77}, + {'c', 635, 249, 71, 82, -3, 75, 77}, + {'d', 758, 0, 69, 109, -3, 102, 77}, + {'e', 563, 249, 72, 82, -2, 75, 77}, + {'f', 495, 0, 73, 111, -4, 105, 77}, + {'g', 898, 0, 69, 108, -3, 75, 77}, + {'h', 1036, 0, 68, 108, -5, 102, 77}, + {'i', 214, 144, 69, 105, -7, 98, 77}, + {'j', 272, 0, 52, 132, -7, 98, 77}, + {'k', 827, 0, 71, 108, -5, 102, 77}, + {'l', 967, 0, 69, 108, -7, 102, 77}, + {'m', 845, 249, 78, 81, 0, 75, 77}, + {'n', 923, 249, 68, 81, -5, 75, 77}, + {'o', 489, 249, 74, 82, -2, 75, 77}, + {'p', 1184, 0, 69, 107, -5, 75, 77}, + {'q', 1253, 0, 69, 107, -3, 75, 77}, + {'r', 1058, 249, 59, 81, -15, 75, 77}, + {'s', 776, 249, 69, 82, -5, 75, 77}, + {'t', 389, 249, 70, 97, -3, 90, 77}, + {'u', 991, 249, 67, 81, -5, 74, 77}, + {'v', 1200, 249, 76, 80, 0, 74, 77}, + {'w', 1117, 249, 83, 80, 3, 74, 77}, + {'x', 1276, 249, 76, 80, -1, 74, 77}, + {'y', 1104, 0, 80, 107, 2, 74, 77}, + {'z', 1352, 249, 70, 80, -4, 74, 77}, + {'{', 164, 0, 54, 135, -14, 106, 77}, + {'|', 394, 0, 22, 128, -28, 97, 77}, + {'}', 218, 0, 54, 135, -14, 106, 77}, + {'~', 1925, 249, 83, 37, 3, 56, 77}, +}; + +static Font font_Roboto_Mono = {"Roboto Mono", 128, 0, 0, 2048, 512, 95, characters_Roboto_Mono}; + +PointWorldText::PointWorldText() +{ + V_memset(m_szText, 0, sizeof(m_szText)); +} + +PointWorldText::PointWorldText(const char* pszText, Vector pos, CMaterialReference* font) +{ + m_vecAbsOrigin = pos; + m_Font = font; + SetText(pszText); +} + +PointWorldText::~PointWorldText() +{ +} + +void PointWorldText::SetText( const char* pszText ) +{ + m_nTextLength = V_strlen( pszText ); + V_strncpy( m_szText, pszText, sizeof(m_szText) ); + UpdateTextWorldSize(); +} + +void PointWorldText::UpdateTextWorldSize() +{ + CalcTextTotalSize( m_flTextWorldWidth, m_flTextWorldHeight ); +} +void PointWorldText::CalcTextTotalSize(float &outWidth, float &outHeight) +{ + outWidth = 0.0f; + outHeight = 0.0f; + + const char *szText = m_szText; + if ( !szText[0] ) + return; + + int nNumChars = m_nTextLength; + if ( !nNumChars ) + return; + + float screenSize = m_flTextSize; + float screenSpacingX = GetTextSpacingX(); + float screenSpacingY = GetTextSpacingY(); + Font* font = &font_Roboto_Mono; + outHeight += font->size; + float flLineWidth = 0.0f; + for ( int i = 0; i < nNumChars; i++ ) + { + char nChar = *(szText++); + unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); + Character *character = &font->characters[ nCharIdx ]; + float scale = screenSize / (float)font->size; + if ( nChar == '\n' ) + { + outWidth = Max( outWidth, flLineWidth ); + flLineWidth = 0.0f; + outHeight += (font->size + screenSpacingY) * scale; + continue; + } + flLineWidth += (character->advance + screenSpacingX) * scale; + } + outWidth = Max( outWidth, flLineWidth ); +} + +float PointWorldText::GetTextWorldWidth() const +{ + return m_flTextWorldWidth; +} +float PointWorldText::GetTextWorldHeight() const +{ + return m_flTextWorldHeight; +} +float PointWorldText::GetTextSpacingX() const +{ + return m_flTextSpacingX; +} +float PointWorldText::GetTextSpacingY() const +{ + return m_flTextSpacingY; +} + +int PointWorldText::DrawModel(float alpha) +{ + const char *szText = m_szText; + if ( !szText[0] ) + return 0; + + int nNumChars = m_nTextLength; + if ( !nNumChars ) + return 0; + + IMaterial* pDebugText = *m_Font; + if ( !pDebugText ) + return 0; + + Vector ViewForward( 1.0f, 0.0f, 0.0f ); + Vector ViewUp( 0.0f, 1.0f, 0.0f ); + Vector ViewRight( 0.0f, 0.0f, -1.0f ); + Vector vecStartPos; + VectorCopy( GetAbsOrigin(), vecStartPos ); + + float screenSize = m_flTextSize; + float screenSpacingX = GetTextSpacingX(); + float screenSpacingY = GetTextSpacingY(); + + switch ( m_nOrientation ) + { + // always orient towards screen + case 1: + ViewForward = -CurrentViewForward(); + ViewUp = CurrentViewUp(); + ViewRight = CurrentViewRight(); + // center the text for nicer rotation + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; + // orient towards screen but align with Z axis + case 2: + ViewForward = -CurrentViewForward(); + ViewUp = Vector(0, 0, 1); + ViewRight = CurrentViewRight(); + // center the text for nicer rotation + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; + // entity orientation + default: + AngleVectors( GetAbsAngles(), &ViewForward, &ViewRight, &ViewUp ); + break; + } + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->Bind( pDebugText ); + pDebugText->IncrementReferenceCount(); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, nNumChars ); + + Vector vecOrigStartPos = vecStartPos; + + Font *font = &font_Roboto_Mono; + + color32 color = m_colTextColor; + color.a *= alpha; + + byte* pColor = (byte*)&color; + + for ( int i = 0; i < nNumChars; i++ ) + { + char nChar = *(szText++); + unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); + Character *character = &font->characters[ nCharIdx ]; + float scale = screenSize / (float)font->size; + if ( nChar == '\n' ) + { + vecOrigStartPos -= ( ViewUp * ( (font->size + screenSpacingY) * scale ) ); + vecStartPos = vecOrigStartPos; + continue; + } + if ( nChar != ' ' ) + { + float x, y, s, t; + + x = -character->originX; + y = -character->originY; + s = character->x / (float)font->width; + t = character->y / (float)font->height; + Vector v0 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v0.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX; + y = -character->originY + character->height; + s = character->x / (float)font->width; + t = (character->y + character->height) / (float)font->height; + Vector v2 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v2.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX + character->width; + y = -character->originY + character->height; + s = (character->x + character->width) / (float)font->width; + t = (character->y + character->height) / (float)font->height; + Vector v3 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v3.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + + x = -character->originX + character->width; + y = -character->originY; + s = (character->x + character->width) / (float)font->width; + t = (character->y) / (float)font->height; + Vector v1 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; + meshBuilder.Position3fv( v1.Base() ); + meshBuilder.TexCoord2f( 0, s, t ); + meshBuilder.Color4ubv( pColor ); + meshBuilder.AdvanceVertex(); + } + vecStartPos += ViewRight * ((character->advance + screenSpacingX) * scale); + } + meshBuilder.End(); + pMesh->Draw(); + return 1; +} \ No newline at end of file diff --git a/src/game/client/neo/c_neo_point_world_text.h b/src/game/client/neo/c_neo_point_world_text.h new file mode 100644 index 000000000..b1acfab24 --- /dev/null +++ b/src/game/client/neo/c_neo_point_world_text.h @@ -0,0 +1,43 @@ +/////////////////////////////////////////////// +// A non-networked non-entity PointWorldText // +/////////////////////////////////////////////// + +class PointWorldText +{ +public: + PointWorldText(); + PointWorldText(const char* pszText, Vector pos, CMaterialReference* font); + ~PointWorldText(); + + int DrawModel(float alpha = 1.0f); + + void SetText(const char* pszText); + + Vector GetAbsOrigin() { return m_vecAbsOrigin; } + QAngle GetAbsAngles() { return m_vecAbsAngles; } + +private: + void CalcTextTotalSize(float &outWidth, float &outHeight); + void UpdateTextWorldSize(); + + float GetTextWorldWidth() const; + float GetTextWorldHeight() const; + float GetTextSpacingX() const; + float GetTextSpacingY() const; + + Vector m_vecAbsOrigin = {0, 0, 0}; + QAngle m_vecAbsAngles = {0, 0, 0}; + + char m_szText[ MAX_PLACE_NAME_LENGTH ]; + float m_flTextSize = 96.f; + float m_flTextSpacingX = 0.f; + float m_flTextSpacingY = 0.f; + color32 m_colTextColor = {255, 255, 255, 255}; + int m_nOrientation = 2; + int m_nTextLength = 0; + + float m_flTextWorldWidth = 0.f; + float m_flTextWorldHeight = 0.f; + + CMaterialReference* m_Font; +}; \ No newline at end of file diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp index 0b3450097..7b002ed98 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.cpp +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -14,10 +14,11 @@ NEO_HUD_ELEMENT_DECLARE_FREQ_CVAR(PlaceName, 0.1) static CNEOHud_PlaceName *g_PlaceName = nullptr; -static const char* TEXT_MATERIAL = "editor/worldtext_9"; ConVar cl_neo_hud_place_names_depth_test("cl_neo_hud_place_names_depth_test", "0", FCVAR_ARCHIVE, "Depth test in-world nearby place names", true, 0.0f, true, 1.0f, [](IConVar* var, const char* pOldValue, float flOldValue)->void{ - PrecacheMaterial( TEXT_MATERIAL ); + if (!g_PlaceName) + return; + IMaterial* textMaterial = g_PlaceName->GetFont(); if (!textMaterial) return; @@ -25,11 +26,10 @@ ConVar cl_neo_hud_place_names_depth_test("cl_neo_hud_place_names_depth_test", "0 textMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, !cl_neo_hud_place_names_depth_test.GetBool() ); }); +const char* TEXT_MATERIAL = "editor/worldtext_9"; CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent) : CHudElement(pElementName), Panel(parent, pElementName) { - g_PlaceName = this; - SetAutoDelete(true); m_iHideHudElementNumber = NEO_HUD_ELEMENT_PLACE_NAME; @@ -41,20 +41,24 @@ CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *pare SetParent(g_pClientMode->GetViewport()); } - m_szPlaceName[0] = L'\0'; - SetVisible(true); + g_PlaceName = this; + m_szPlaceName[0] = L'\0'; + PrecacheMaterial( TEXT_MATERIAL ); m_Font.Init(TEXT_MATERIAL, TEXTURE_GROUP_PRECACHED, true); - const PointWorldText foo = { "Important Place", {100, 100, 400}}; + const PointWorldText foo = {"Important Place", {100, 100, 400}, &m_Font}; places.AddToTail(foo); } CNEOHud_PlaceName::~CNEOHud_PlaceName() { - g_PlaceName = nullptr; + if (g_PlaceName == this) + { + g_PlaceName = nullptr; + } } void CNEOHud_PlaceName::ApplySchemeSettings(vgui::IScheme* pScheme) @@ -114,9 +118,9 @@ void CNEOHud_PlaceName::UpdateStateForNeoHudElementDraw() ConVar cl_neo_hud_curent_place_name_draw("cl_neo_hud_curent_place_name_draw", "1", FCVAR_ARCHIVE, "Draw the current place name", true, 0.0f, true, 1.0f); -static bool bShouldDrawPlaceNames = false; -static ConCommand startshowplacenames("+showplacenames", [](const CCommand& args)->void {bShouldDrawPlaceNames = true; }); -static ConCommand endshowplacenames("-showplacenames", [](const CCommand& args)->void {bShouldDrawPlaceNames = false; }); +static bool shouldDrawPlaceNames = false; +static ConCommand startshowplacenames("+showplacenames", [](const CCommand& args)->void {shouldDrawPlaceNames = true; }); +static ConCommand endshowplacenames("-showplacenames", [](const CCommand& args)->void {shouldDrawPlaceNames = false; }); static float placeNamesRadiusSquared = 0.0f; ConVar cl_neo_hud_place_names_radius("cl_neo_hud_place_names_radius", "2048", FCVAR_ARCHIVE, "Radius from the camera within which to draw the names of all nearby places", true, 0.0f, false, 0.0f, @@ -144,23 +148,30 @@ void CNEOHud_PlaceName::Paint() PaintNeoElement(); } -static float flPlaceNameOpacity = 0.f; +static float placeNameAlpha = 0.f; void CNEOHud_PlaceName::DrawPlaceNames() { constexpr int ANIMATION_SPEED = 2; - if (bShouldDrawPlaceNames) + if (shouldDrawPlaceNames) { - flPlaceNameOpacity = min(1.0f, flPlaceNameOpacity + (gpGlobals->frametime * ANIMATION_SPEED)); + placeNameAlpha = min(1.0f, placeNameAlpha + (gpGlobals->frametime * ANIMATION_SPEED)); } else { - flPlaceNameOpacity = max(0.0f, flPlaceNameOpacity - (gpGlobals->frametime * ANIMATION_SPEED)); + placeNameAlpha = max(0.0f, placeNameAlpha - (gpGlobals->frametime * ANIMATION_SPEED)); } - if (flPlaceNameOpacity) + if (placeNameAlpha) { for (PointWorldText place : places) { - place.DrawModel(); + float alpha = placeNameAlpha; + const float distanceSquared = MainViewOrigin().DistToSqr(place.GetAbsOrigin()); + if (distanceSquared > placeNamesRadiusSquared) + { + alpha *= 1.f - min(1.f, ((distanceSquared - placeNamesRadiusSquared) / placeNamesRadiusSquared)); + } + + place.DrawModel(alpha); } } } @@ -169,333 +180,3 @@ CNEOHud_PlaceName* GetPlaceName() { return g_PlaceName; } - -typedef struct Character { - int codePoint, x, y, width, height, originX, originY, advance; -} Character; - -typedef struct Font { - const char *name; - int size, bold, italic, width, height, characterCount; - Character *characters; -} Font; - -static Character characters_Roboto_Mono[] = { - {' ', 167, 352, 12, 12, 6, 6, 77}, - {'!', 675, 144, 27, 104, -24, 97, 77}, - {'"', 1859, 249, 44, 42, -16, 102, 77}, - {'#', 702, 144, 82, 103, 2, 97, 77}, - {'$', 324, 0, 70, 131, -4, 112, 77}, - {'%', 1322, 0, 83, 106, 3, 98, 77}, - {'&', 1405, 0, 80, 106, -1, 98, 77}, - {'\'', 1903, 249, 22, 42, -25, 102, 77}, - {'(', 0, 0, 45, 144, -16, 109, 77}, - {')', 45, 0, 45, 144, -14, 109, 77}, - {'*', 1497, 249, 72, 73, -4, 97, 77}, - {'+', 1422, 249, 75, 78, -1, 81, 77}, - {',', 1829, 249, 30, 47, -16, 20, 77}, - {'-', 37, 352, 60, 22, -8, 51, 77}, - {'.', 2008, 249, 30, 30, -25, 22, 77}, - {'/', 568, 0, 60, 111, -10, 97, 77}, - {'0', 1788, 0, 71, 106, -3, 98, 77}, - {'1', 342, 249, 47, 103, -7, 97, 77}, - {'2', 0, 144, 74, 105, 1, 98, 77}, - {'3', 1859, 0, 70, 106, 0, 98, 77}, - {'4', 1263, 144, 78, 103, 1, 97, 77}, - {'5', 572, 144, 69, 104, -6, 97, 77}, - {'6', 74, 144, 70, 105, -3, 97, 77}, - {'7', 1491, 144, 73, 103, -1, 97, 77}, - {'8', 1929, 0, 70, 106, -5, 98, 77}, - {'9', 144, 144, 70, 105, -3, 98, 77}, - {':', 459, 249, 30, 85, -28, 77, 77}, - {';', 641, 144, 34, 104, -24, 77, 77}, - {'<', 1636, 249, 65, 69, -5, 75, 77}, - {'=', 1761, 249, 68, 48, -5, 65, 77}, - {'>', 1569, 249, 67, 69, -5, 75, 77}, - {'?', 283, 144, 66, 105, -6, 98, 77}, - {'@', 349, 144, 80, 104, 2, 97, 77}, - {'A', 865, 144, 80, 103, 1, 97, 77}, - {'B', 1852, 144, 71, 103, -5, 97, 77}, - {'C', 1713, 0, 75, 106, -1, 98, 77}, - {'D', 1417, 144, 74, 103, -4, 97, 77}, - {'E', 71, 249, 68, 103, -5, 97, 77}, - {'F', 139, 249, 68, 103, -6, 97, 77}, - {'G', 1485, 0, 76, 106, 0, 98, 77}, - {'H', 1923, 144, 71, 103, -3, 97, 77}, - {'I', 275, 249, 67, 103, -5, 97, 77}, - {'J', 501, 144, 71, 104, 0, 97, 77}, - {'K', 1341, 144, 76, 103, -5, 97, 77}, - {'L', 207, 249, 68, 103, -6, 97, 77}, - {'M', 1564, 144, 72, 103, -3, 97, 77}, - {'N', 0, 249, 71, 103, -3, 97, 77}, - {'O', 1561, 0, 76, 106, -1, 98, 77}, - {'P', 1636, 144, 72, 103, -6, 97, 77}, - {'Q', 416, 0, 79, 120, 0, 98, 77}, - {'R', 1708, 144, 72, 103, -5, 97, 77}, - {'S', 1637, 0, 76, 106, -1, 98, 77}, - {'T', 945, 144, 80, 103, 1, 97, 77}, - {'U', 429, 144, 72, 104, -3, 97, 77}, - {'V', 1105, 144, 79, 103, 1, 97, 77}, - {'W', 784, 144, 81, 103, 1, 97, 77}, - {'X', 1184, 144, 79, 103, 0, 97, 77}, - {'Y', 1025, 144, 80, 103, 2, 97, 77}, - {'Z', 1780, 144, 72, 103, -1, 97, 77}, - {'[', 90, 0, 37, 136, -21, 110, 77}, - {'\\', 628, 0, 60, 111, -9, 97, 77}, - {']', 127, 0, 37, 136, -19, 110, 77}, - {'^', 1701, 249, 60, 61, -9, 97, 77}, - {'_', 97, 352, 70, 21, -4, 6, 77}, - {'`', 0, 352, 37, 29, -20, 99, 77}, - {'a', 706, 249, 70, 82, -4, 75, 77}, - {'b', 688, 0, 70, 109, -5, 102, 77}, - {'c', 635, 249, 71, 82, -3, 75, 77}, - {'d', 758, 0, 69, 109, -3, 102, 77}, - {'e', 563, 249, 72, 82, -2, 75, 77}, - {'f', 495, 0, 73, 111, -4, 105, 77}, - {'g', 898, 0, 69, 108, -3, 75, 77}, - {'h', 1036, 0, 68, 108, -5, 102, 77}, - {'i', 214, 144, 69, 105, -7, 98, 77}, - {'j', 272, 0, 52, 132, -7, 98, 77}, - {'k', 827, 0, 71, 108, -5, 102, 77}, - {'l', 967, 0, 69, 108, -7, 102, 77}, - {'m', 845, 249, 78, 81, 0, 75, 77}, - {'n', 923, 249, 68, 81, -5, 75, 77}, - {'o', 489, 249, 74, 82, -2, 75, 77}, - {'p', 1184, 0, 69, 107, -5, 75, 77}, - {'q', 1253, 0, 69, 107, -3, 75, 77}, - {'r', 1058, 249, 59, 81, -15, 75, 77}, - {'s', 776, 249, 69, 82, -5, 75, 77}, - {'t', 389, 249, 70, 97, -3, 90, 77}, - {'u', 991, 249, 67, 81, -5, 74, 77}, - {'v', 1200, 249, 76, 80, 0, 74, 77}, - {'w', 1117, 249, 83, 80, 3, 74, 77}, - {'x', 1276, 249, 76, 80, -1, 74, 77}, - {'y', 1104, 0, 80, 107, 2, 74, 77}, - {'z', 1352, 249, 70, 80, -4, 74, 77}, - {'{', 164, 0, 54, 135, -14, 106, 77}, - {'|', 394, 0, 22, 128, -28, 97, 77}, - {'}', 218, 0, 54, 135, -14, 106, 77}, - {'~', 1925, 249, 83, 37, 3, 56, 77}, -}; - -static Font font_Roboto_Mono = {"Roboto Mono", 128, 0, 0, 2048, 512, 95, characters_Roboto_Mono}; - -PointWorldText::PointWorldText() -{ - PrecacheMaterial( TEXT_MATERIAL ); - - V_memset(m_szText, 0, sizeof(m_szText)); -} - -PointWorldText::PointWorldText(const char* pszText, Vector pos) -{ - PrecacheMaterial( TEXT_MATERIAL ); - - SetText(pszText); - m_vecAbsOrigin = pos; -} - -PointWorldText::~PointWorldText() -{ -} - -void PointWorldText::SetText( const char* pszText ) -{ - m_nTextLength = V_strlen( pszText ); - V_strncpy( m_szText, pszText, sizeof(m_szText) ); - UpdateTextWorldSize(); -} - -void PointWorldText::UpdateTextWorldSize() -{ - CalcTextTotalSize( m_flTextWorldWidth, m_flTextWorldHeight ); -} -void PointWorldText::CalcTextTotalSize(float &outWidth, float &outHeight) -{ - outWidth = 0.0f; - outHeight = 0.0f; - - const char *szText = m_szText; - if ( !szText[0] ) - return; - - int nNumChars = m_nTextLength; - if ( !nNumChars ) - return; - - float screenSize = m_flTextSize; - float screenSpacingX = GetTextSpacingX(); - float screenSpacingY = GetTextSpacingY(); - Font* font = &font_Roboto_Mono; - outHeight += font->size; - float flLineWidth = 0.0f; - for ( int i = 0; i < nNumChars; i++ ) - { - char nChar = *(szText++); - unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); - Character *character = &font->characters[ nCharIdx ]; - float scale = screenSize / (float)font->size; - if ( nChar == '\n' ) - { - outWidth = Max( outWidth, flLineWidth ); - flLineWidth = 0.0f; - outHeight += (font->size + screenSpacingY) * scale; - continue; - } - flLineWidth += (character->advance + screenSpacingX) * scale; - } - outWidth = Max( outWidth, flLineWidth ); -} - -float PointWorldText::GetTextWorldWidth() const -{ - return m_flTextWorldWidth; -} -float PointWorldText::GetTextWorldHeight() const -{ - return m_flTextWorldHeight; -} -float PointWorldText::GetTextSpacingX() const -{ - return m_flTextSpacingX; -} -float PointWorldText::GetTextSpacingY() const -{ - return m_flTextSpacingY; -} - -int PointWorldText::DrawModel( ) -{ - const char *szText = m_szText; - if ( !szText[0] ) - return 0; - - int nNumChars = m_nTextLength; - if ( !nNumChars ) - return 0; - - if (!g_PlaceName) - return 0; - - IMaterial* pDebugText = g_PlaceName->GetFont(); - if ( !pDebugText ) - return 0; - - Vector ViewForward( 1.0f, 0.0f, 0.0f ); - Vector ViewUp( 0.0f, 1.0f, 0.0f ); - Vector ViewRight( 0.0f, 0.0f, -1.0f ); - Vector vecStartPos; - VectorCopy( GetAbsOrigin(), vecStartPos ); - - float screenSize = m_flTextSize; - float screenSpacingX = GetTextSpacingX(); - float screenSpacingY = GetTextSpacingY(); - - switch ( m_nOrientation ) - { - // always orient towards screen - case 1: - ViewForward = -CurrentViewForward(); - ViewUp = CurrentViewUp(); - ViewRight = CurrentViewRight(); - // center the text for nicer rotation - vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; - break; - // orient towards screen but align with Z axis - case 2: - ViewForward = -CurrentViewForward(); - ViewUp = Vector(0, 0, 1); - ViewRight = CurrentViewRight(); - // center the text for nicer rotation - vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; - break; - // entity orientation - default: - AngleVectors( GetAbsAngles(), &ViewForward, &ViewRight, &ViewUp ); - break; - } - - CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); - pRenderContext->Bind( pDebugText ); - pDebugText->IncrementReferenceCount(); - - IMesh* pMesh = pRenderContext->GetDynamicMesh(); - - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_QUADS, nNumChars ); - - Vector vecOrigStartPos = vecStartPos; - - Font *font = &font_Roboto_Mono; - - color32 color = m_colTextColor; - color.a *= flPlaceNameOpacity; - const float distanceSquared = MainViewOrigin().DistToSqr(GetAbsOrigin()); - if (distanceSquared > placeNamesRadiusSquared) - { - color.a *= 1.f - min(1.f, ((distanceSquared - placeNamesRadiusSquared) / placeNamesRadiusSquared)); - } - byte* pColor = (byte*)&color; - - for ( int i = 0; i < nNumChars; i++ ) - { - char nChar = *(szText++); - unsigned int nCharIdx = Clamp( ( unsigned int )( nChar ) - 32, 0u, ( unsigned int )( ARRAYSIZE( characters_Roboto_Mono ) - 1u ) ); - Character *character = &font->characters[ nCharIdx ]; - float scale = screenSize / (float)font->size; - if ( nChar == '\n' ) - { - vecOrigStartPos -= ( ViewUp * ( (font->size + screenSpacingY) * scale ) ); - vecStartPos = vecOrigStartPos; - continue; - } - if ( nChar != ' ' ) - { - float x, y, s, t; - - x = -character->originX; - y = -character->originY; - s = character->x / (float)font->width; - t = character->y / (float)font->height; - Vector v0 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; - meshBuilder.Position3fv( v0.Base() ); - meshBuilder.TexCoord2f( 0, s, t ); - meshBuilder.Color4ubv( pColor ); - meshBuilder.AdvanceVertex(); - - x = -character->originX; - y = -character->originY + character->height; - s = character->x / (float)font->width; - t = (character->y + character->height) / (float)font->height; - Vector v2 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; - meshBuilder.Position3fv( v2.Base() ); - meshBuilder.TexCoord2f( 0, s, t ); - meshBuilder.Color4ubv( pColor ); - meshBuilder.AdvanceVertex(); - - x = -character->originX + character->width; - y = -character->originY + character->height; - s = (character->x + character->width) / (float)font->width; - t = (character->y + character->height) / (float)font->height; - Vector v3 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; - meshBuilder.Position3fv( v3.Base() ); - meshBuilder.TexCoord2f( 0, s, t ); - meshBuilder.Color4ubv( pColor ); - meshBuilder.AdvanceVertex(); - - x = -character->originX + character->width; - y = -character->originY; - s = (character->x + character->width) / (float)font->width; - t = (character->y) / (float)font->height; - Vector v1 = vecStartPos + ViewRight * x * scale + ViewUp * (- y) * scale; - meshBuilder.Position3fv( v1.Base() ); - meshBuilder.TexCoord2f( 0, s, t ); - meshBuilder.Color4ubv( pColor ); - meshBuilder.AdvanceVertex(); - } - vecStartPos += ViewRight * ((character->advance + screenSpacingX) * scale); - } - meshBuilder.End(); - pMesh->Draw(); - return 1; -} \ No newline at end of file diff --git a/src/game/client/neo/ui/neo_hud_place_name.h b/src/game/client/neo/ui/neo_hud_place_name.h index 558c5059c..54cb7c024 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.h +++ b/src/game/client/neo/ui/neo_hud_place_name.h @@ -2,47 +2,9 @@ #include "neo_hud_childelement.h" #include "hudelement.h" +#include "c_neo_point_world_text.h" #include -class PointWorldText -{ -public: - PointWorldText(); - PointWorldText(const char* pszText, Vector pos); - ~PointWorldText(); - - int DrawModel(); - - void SetText(const char* pszText); - void SetFont(int nFont); - - Vector GetAbsOrigin() { return m_vecAbsOrigin; } - QAngle GetAbsAngles() { return m_vecAbsAngles; } - -private: - void CalcTextTotalSize(float &outWidth, float &outHeight); - void UpdateTextWorldSize(); - - float GetTextWorldWidth() const; - float GetTextWorldHeight() const; - float GetTextSpacingX() const; - float GetTextSpacingY() const; - - Vector m_vecAbsOrigin = {0, 0, 0}; - QAngle m_vecAbsAngles = {0, 0, 0}; - - char m_szText[ MAX_PLACE_NAME_LENGTH ]; - float m_flTextSize = 100.f; - float m_flTextSpacingX = 0.f; - float m_flTextSpacingY = 0.f; - color32 m_colTextColor = {255, 255, 255, 255}; - int m_nOrientation = 2; - int m_nTextLength = 0; - - float m_flTextWorldWidth = 0.f; - float m_flTextWorldHeight = 0.f; -}; - class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, public vgui::Panel { DECLARE_CLASS_SIMPLE(CNEOHud_PlaceName, Panel); From 2471e3c47e5de2ba2c65b369ea2b551082c998ce Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Thu, 27 Aug 2026 18:58:37 +0100 Subject: [PATCH 05/14] grab place names from nav mesh --- .../client/neo/c_neo_point_world_text.cpp | 8 + src/game/client/neo/c_neo_point_world_text.h | 4 +- src/game/client/neo/ui/neo_hud_place_name.cpp | 145 +++++++++++++++++- src/game/client/neo/ui/neo_hud_place_name.h | 23 ++- src/game/client/viewrender.cpp | 2 +- src/game/server/nav_file.cpp | 17 +- src/game/server/nav_mesh.cpp | 14 +- src/game/server/nav_mesh.h | 3 +- src/game/shared/neo/nav_file_shared.cpp | 0 src/game/shared/neo/nav_file_shared.h | 0 10 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 src/game/shared/neo/nav_file_shared.cpp create mode 100644 src/game/shared/neo/nav_file_shared.h diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp index 9294ada12..4ce81f432 100644 --- a/src/game/client/neo/c_neo_point_world_text.cpp +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -234,6 +234,14 @@ int PointWorldText::DrawModel(float alpha) // center the text for nicer rotation vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; break; + // orient along vector from origin to camera origin, aligned with z axis + case 3: + ViewForward = -CurrentViewOrigin() + GetAbsOrigin(); + ViewUp = Vector(0, 0, 1); + ViewRight = ViewForward.Cross(ViewUp).Normalized(); + // center the text for nicer rotation + vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; + break; // entity orientation default: AngleVectors( GetAbsAngles(), &ViewForward, &ViewRight, &ViewUp ); diff --git a/src/game/client/neo/c_neo_point_world_text.h b/src/game/client/neo/c_neo_point_world_text.h index b1acfab24..803297a30 100644 --- a/src/game/client/neo/c_neo_point_world_text.h +++ b/src/game/client/neo/c_neo_point_world_text.h @@ -29,11 +29,11 @@ class PointWorldText QAngle m_vecAbsAngles = {0, 0, 0}; char m_szText[ MAX_PLACE_NAME_LENGTH ]; - float m_flTextSize = 96.f; + float m_flTextSize = 64.f; float m_flTextSpacingX = 0.f; float m_flTextSpacingY = 0.f; color32 m_colTextColor = {255, 255, 255, 255}; - int m_nOrientation = 2; + int m_nOrientation = 3; int m_nTextLength = 0; float m_flTextWorldWidth = 0.f; diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp index 7b002ed98..a67235e8f 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.cpp +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -4,6 +4,7 @@ #include #include "c_neo_player.h" #include "view.h" +#include "tier1/lzmaDecoder.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -48,9 +49,6 @@ CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *pare PrecacheMaterial( TEXT_MATERIAL ); m_Font.Init(TEXT_MATERIAL, TEXTURE_GROUP_PRECACHED, true); - - const PointWorldText foo = {"Important Place", {100, 100, 400}, &m_Font}; - places.AddToTail(foo); } CNEOHud_PlaceName::~CNEOHud_PlaceName() @@ -176,6 +174,147 @@ void CNEOHud_PlaceName::DrawPlaceNames() } } +#if defined( _X360 ) + #define FORMAT_BSPFILE "maps\\%s.360.bsp" + #define FORMAT_NAVFILE "maps\\%s.360.nav" +#else + #define FORMAT_BSPFILE "maps\\%s.bsp" +#ifdef NEO + #define FORMAT_NAVFILE "maps\\nav\\%s.nav" +#else + #define FORMAT_NAVFILE "maps\\%s.nav" +#endif // NEO + #define PATH_NAVFILE_EMBEDDED "maps\\embed.nav" +#endif + +//-------------------------------------------------------------------------------------------------------------- +/** + * Fetch raw nav data into buffer + */ +NavErrorType CNEOHud_PlaceName::GetNavDataFromFile( CUtlBuffer &outBuffer, bool *pNavDataFromBSP ) +{ + char maptmp[256]; + Q_FileBase( engine->GetLevelName(), maptmp, sizeof( maptmp) ); + const char* pszMapName = maptmp; + + // nav filename is derived from map filename + char filename[MAX_PATH] = { 0 }; + Q_snprintf( filename, sizeof( filename ), FORMAT_NAVFILE, pszMapName ); + + if ( !filesystem->ReadFile( filename, "MOD", outBuffer ) ) // this ignores .nav files embedded in the .bsp ... + { + if ( !filesystem->ReadFile( filename, "BSP", outBuffer ) ) // ... and this looks for one if it's the only one around. + { + // Finally, check for the special embed name for in-BSP nav meshes only + if ( !filesystem->ReadFile( PATH_NAVFILE_EMBEDDED, "BSP", outBuffer ) ) + { + return NAV_CANT_ACCESS_FILE; + } + } + if ( pNavDataFromBSP ) + { + *pNavDataFromBSP = true; + } + } + + if ( IsX360() ) + { + // 360 has compressed NAVs + if ( CLZMA::IsCompressed( (unsigned char *)outBuffer.Base() ) ) + { + int originalSize = CLZMA::GetActualSize( (unsigned char *)outBuffer.Base() ); + unsigned char *pOriginalData = new unsigned char[originalSize]; + CLZMA::Uncompress( (unsigned char *)outBuffer.Base(), pOriginalData ); + outBuffer.AssumeMemory( pOriginalData, originalSize, originalSize, CUtlBuffer::READ_ONLY ); + } + } + + return NAV_OK; +} + +#define NAV_MAGIC_NUMBER 0xFEEDFACE // to help identify nav files + +const int NavCurrentVersion = 17; + +typedef unsigned short IndexType; // Loaded/Saved as UnsignedShort. Change this and you'll have to version. + +//-------------------------------------------------------------------------------------------------------------- +/** + * Reads the used place names from the nav file (can be used to selectively precache before the nav is loaded) + */ +void CNEOHud_PlaceName::GetPlacesFromNavFile() +{ + places.RemoveAll(); + // nav filename is derived from map filename + char filename[256]; + Q_snprintf( filename, sizeof( filename ), FORMAT_NAVFILE, STRING( engine->GetLevelName() ) ); + + CUtlBuffer fileBuffer( 4096, 1024*1024, CUtlBuffer::READ_ONLY ); + if ( GetNavDataFromFile( fileBuffer ) != NAV_OK ) + { + return; + } + + // check magic number + unsigned int magic = fileBuffer.GetUnsignedInt(); + if ( !fileBuffer.IsValid() || magic != NAV_MAGIC_NUMBER ) + { + return; // Corrupt nav file? + } + + // read file version number + unsigned int version = fileBuffer.GetUnsignedInt(); + if ( !fileBuffer.IsValid() || version > NavCurrentVersion ) + { + return; // Unknown nav file version + } + + if ( version < 17 ) + { + return; // Too old to have place names and their average origin + } + + unsigned int subVersion = 0; + if ( version >= 10 ) + { + subVersion = fileBuffer.GetUnsignedInt(); + if ( !fileBuffer.IsValid() ) + { + return; // No sub-version + } + } + + fileBuffer.GetUnsignedInt(); // skip BSP file size + if ( version >= 14 ) + { + fileBuffer.GetUnsignedChar(); // skip m_isAnalyzed + } + + { + // read number of entries + IndexType count = fileBuffer.GetUnsignedShort(); + + places.RemoveAll(); + + // read each entry + char placeName[256]; + unsigned short len; + for( int i=0; i -class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, public vgui::Panel +enum NavErrorType +{ + NAV_OK, + NAV_CANT_ACCESS_FILE, + NAV_INVALID_FILE, + NAV_BAD_FILE_VERSION, + NAV_FILE_OUT_OF_DATE, + NAV_CORRUPT_DATA, + NAV_OUT_OF_MEMORY, +}; + +class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, public vgui::Panel, public CAutoGameSystem { DECLARE_CLASS_SIMPLE(CNEOHud_PlaceName, Panel); @@ -24,6 +35,16 @@ class CNEOHud_PlaceName : public CNEOHud_ChildElement, public CHudElement, publi private: CNEOHud_PlaceName(const CNEOHud_PlaceName&other); + + NavErrorType GetNavDataFromFile(CUtlBuffer& outBuffer, bool* pNavDataFromBSP = nullptr); + void GetPlacesFromNavFile(); + + // CAutoGameSystem + + virtual void LevelInitPostEntity() override + { + GetPlacesFromNavFile(); + } wchar_t m_szPlaceName[MAX_PLACE_NAME_LENGTH]; int textXOffset = 0; diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index 82b57f4cc..97cb83b32 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -2003,7 +2003,7 @@ void CViewRender::RenderPlayerSprites() #ifdef NEO //----------------------------------------------------------------------------- -// Purpose: Renders voice feedback and other sprites attached to players +// Purpose: Renders navigation mesh place names // Input : none //----------------------------------------------------------------------------- void CViewRender::RenderPlaceNames() diff --git a/src/game/server/nav_file.cpp b/src/game/server/nav_file.cpp index 8959a3d2c..ab38e4479 100644 --- a/src/game/server/nav_file.cpp +++ b/src/game/server/nav_file.cpp @@ -44,7 +44,11 @@ /// IMPORTANT: If this version changes, the swap function in makegamedata /// must be updated to match. If not, this will break the Xbox 360. // TODO: Was changed from 15, update when latest 360 code is integrated (MSB 5/5/09) +#ifdef NEO +const int NavCurrentVersion = 17; // Version 17 Places now store average origin +#else const int NavCurrentVersion = 16; +#endif // NEO //-------------------------------------------------------------------------------------------------------------- // @@ -142,6 +146,10 @@ void PlaceDirectory::Save( CUtlBuffer &fileBuffer ) unsigned short len = (unsigned short)(strlen( placeName ) + 1); fileBuffer.PutUnsignedShort( len ); fileBuffer.Put( placeName, len ); +#ifdef NEO + Vector averageOrigin = TheNavMesh->PlaceToLocation(m_directory[i]); + fileBuffer.Put(&averageOrigin, 3 * sizeof(float)); +#endif // NEO } fileBuffer.PutUnsignedChar( m_hasUnnamedAreas ); @@ -156,19 +164,16 @@ void PlaceDirectory::Load( CUtlBuffer &fileBuffer, int version ) m_directory.RemoveAll(); // read each entry -#ifdef NEO - char placeName[MAX_PLACE_NAME_LENGTH]; -#else char placeName[256]; -#endif // NEO unsigned short len; for( int i=0; iNextPlace(placeName); + [[maybe_unused]] Vector averageOrigin; // origin will be recalculated when all the nav areas are loaded + fileBuffer.Get(&averageOrigin, 3 * sizeof(float)); + TheNavMesh->LoadPlace(placeName); #endif // NEO Place place = TheNavMesh->NameToPlace( placeName ); if (place == UNDEFINED_PLACE) diff --git a/src/game/server/nav_mesh.cpp b/src/game/server/nav_mesh.cpp index 4dd8d99ca..4cea3bb92 100644 --- a/src/game/server/nav_mesh.cpp +++ b/src/game/server/nav_mesh.cpp @@ -1306,11 +1306,23 @@ Place CNavMesh::PartialNameToPlace( const char *name ) const } #ifdef NEO +//-------------------------------------------------------------------------------------------------------------- +/** + * Given a place, return the average center of all the nav areas belonging to that place. + */ +const Vector CNavMesh::PlaceToLocation( Place place ) const +{ + if (place >= 1 && place <= m_placeName.Count()) + return m_placeName[ (int)place - 1 ].averageCenter; + + return vec3_origin; +} + //-------------------------------------------------------------------------------------------------------------- /** * Return the first unused index in m_placeName */ -Place CNavMesh::NextPlace(const char* name) +Place CNavMesh::LoadPlace(const char* name) { PlaceNameAndCount placeNameAndCount = { "", 0 }; V_strcpy_safe(placeNameAndCount.name, name); diff --git a/src/game/server/nav_mesh.h b/src/game/server/nav_mesh.h index 090d336e5..ecd20fc8f 100644 --- a/src/game/server/nav_mesh.h +++ b/src/game/server/nav_mesh.h @@ -343,7 +343,8 @@ class CNavMesh : public CGameEventListener Place PartialNameToPlace( const char *name ) const; // given the first part of a place name, return a place ID or zero if no place is defined, or the partial match is ambiguous void PrintAllPlaces( void ) const; // output a list of names to the console #ifdef NEO - Place NextPlace(const char* name); + const Vector PlaceToLocation(Place place) const; + Place LoadPlace(const char* name); Place NextAvailablePlace(const char* name); void IncrementNumPlaces(Place place, CNavArea* area); void DecrementNumPlaces(Place place, CNavArea* area); diff --git a/src/game/shared/neo/nav_file_shared.cpp b/src/game/shared/neo/nav_file_shared.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/game/shared/neo/nav_file_shared.h b/src/game/shared/neo/nav_file_shared.h new file mode 100644 index 000000000..e69de29bb From 1e7a8c94e6a204a03e490acdab1736409cba8220 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Fri, 28 Aug 2026 20:38:29 +0100 Subject: [PATCH 06/14] move common enums to nav_shared, final touches --- game/neo/cfg/callout.cfg | 5 + src/game/client/CMakeLists.txt | 1 + .../client/neo/c_neo_point_world_text.cpp | 55 +-- src/game/client/neo/c_neo_point_world_text.h | 29 +- src/game/client/neo/ui/neo_hud_place_name.cpp | 335 ++++++++++++++---- src/game/client/neo/ui/neo_hud_place_name.h | 14 +- src/game/client/viewrender.cpp | 5 +- src/game/server/CMakeLists.txt | 1 + src/game/server/nav.h | 10 +- src/game/server/nav_area.cpp | 4 + src/game/server/nav_area.h | 4 + src/game/server/nav_file.cpp | 22 +- src/game/shared/neo/nav_file_shared.cpp | 0 src/game/shared/neo/nav_file_shared.h | 0 src/game/shared/neo/nav_shared.h | 57 +++ 15 files changed, 423 insertions(+), 119 deletions(-) create mode 100644 game/neo/cfg/callout.cfg delete mode 100644 src/game/shared/neo/nav_file_shared.cpp delete mode 100644 src/game/shared/neo/nav_file_shared.h create mode 100644 src/game/shared/neo/nav_shared.h diff --git a/game/neo/cfg/callout.cfg b/game/neo/cfg/callout.cfg new file mode 100644 index 000000000..7fb0173ee --- /dev/null +++ b/game/neo/cfg/callout.cfg @@ -0,0 +1,5 @@ +alias +enablePlacePainting nav_toggle_place_painting +alias -enablePlacePainting nav_toggle_place_painting + +bind mouse1 +enablePlacePainting +bind mouse2 nav_place_pick diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index f8c0a6dfb..2f5a7c40a 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -1752,6 +1752,7 @@ target_sources_grouped( NAME "Source Files\\Shared" FILES ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/nav_shared.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_juggernaut.h diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp index 4ce81f432..b89102eb4 100644 --- a/src/game/client/neo/c_neo_point_world_text.cpp +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -116,7 +116,7 @@ PointWorldText::PointWorldText() V_memset(m_szText, 0, sizeof(m_szText)); } -PointWorldText::PointWorldText(const char* pszText, Vector pos, CMaterialReference* font) +PointWorldText::PointWorldText(char* pszText, Vector pos, CMaterialReference* font) { m_vecAbsOrigin = pos; m_Font = font; @@ -138,6 +138,7 @@ void PointWorldText::UpdateTextWorldSize() { CalcTextTotalSize( m_flTextWorldWidth, m_flTextWorldHeight ); } + void PointWorldText::CalcTextTotalSize(float &outWidth, float &outHeight) { outWidth = 0.0f; @@ -192,19 +193,22 @@ float PointWorldText::GetTextSpacingY() const return m_flTextSpacingY; } -int PointWorldText::DrawModel(float alpha) +void PointWorldText::DrawModel() { const char *szText = m_szText; - if ( !szText[0] ) - return 0; + if (!szText[0]) + return; int nNumChars = m_nTextLength; - if ( !nNumChars ) - return 0; + if (!nNumChars) + return; IMaterial* pDebugText = *m_Font; - if ( !pDebugText ) - return 0; + if (!pDebugText) + return; + + if (m_colTextColor.a <= 0) + return; Vector ViewForward( 1.0f, 0.0f, 0.0f ); Vector ViewUp( 0.0f, 1.0f, 0.0f ); @@ -218,52 +222,57 @@ int PointWorldText::DrawModel(float alpha) switch ( m_nOrientation ) { - // always orient towards screen - case 1: + case POINTWORLDTEXTORIENTATION_VIEW_DIRECTION: ViewForward = -CurrentViewForward(); ViewUp = CurrentViewUp(); ViewRight = CurrentViewRight(); - // center the text for nicer rotation vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; break; - // orient towards screen but align with Z axis - case 2: + case POINTWORLDTEXTORIENTATION_VIEW_DIRECTION_Z_ALIGNED: ViewForward = -CurrentViewForward(); ViewUp = Vector(0, 0, 1); ViewRight = CurrentViewRight(); // center the text for nicer rotation vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; break; - // orient along vector from origin to camera origin, aligned with z axis - case 3: + case POINTWORLDTEXTORIENTATION_VIEW_ORIGIN_Z_ALIGNED: ViewForward = -CurrentViewOrigin() + GetAbsOrigin(); ViewUp = Vector(0, 0, 1); ViewRight = ViewForward.Cross(ViewUp).Normalized(); // center the text for nicer rotation vecStartPos -= GetTextWorldWidth() * 0.5f * ViewRight; break; - // entity orientation + case POINTWORLDTEXTORIENTATION_ENTITY_ORIENTATION: default: AngleVectors( GetAbsAngles(), &ViewForward, &ViewRight, &ViewUp ); break; } + Vector vecOrigStartPos = vecStartPos; + { + Vector screen; + if (bool behind = ScreenTransform(vecStartPos, screen); + behind) + { + Vector vecEndPos = vecStartPos + (ViewRight * GetTextWorldWidth()); + if (bool behind = ScreenTransform(vecEndPos, screen); + behind) + { + return; + } + } + } + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); pRenderContext->Bind( pDebugText ); pDebugText->IncrementReferenceCount(); IMesh* pMesh = pRenderContext->GetDynamicMesh(); - CMeshBuilder meshBuilder; meshBuilder.Begin( pMesh, MATERIAL_QUADS, nNumChars ); - Vector vecOrigStartPos = vecStartPos; - Font *font = &font_Roboto_Mono; - color32 color = m_colTextColor; - color.a *= alpha; - byte* pColor = (byte*)&color; for ( int i = 0; i < nNumChars; i++ ) @@ -326,5 +335,5 @@ int PointWorldText::DrawModel(float alpha) } meshBuilder.End(); pMesh->Draw(); - return 1; + return; } \ No newline at end of file diff --git a/src/game/client/neo/c_neo_point_world_text.h b/src/game/client/neo/c_neo_point_world_text.h index 803297a30..9b0206a6d 100644 --- a/src/game/client/neo/c_neo_point_world_text.h +++ b/src/game/client/neo/c_neo_point_world_text.h @@ -2,16 +2,33 @@ // A non-networked non-entity PointWorldText // /////////////////////////////////////////////// +#include "neo_player_shared.h" + +enum PointWorldTextOrientation +{ + POINTWORLDTEXTORIENTATION_ENTITY_ORIENTATION = 0, + POINTWORLDTEXTORIENTATION_VIEW_DIRECTION, + POINTWORLDTEXTORIENTATION_VIEW_DIRECTION_Z_ALIGNED, + POINTWORLDTEXTORIENTATION_VIEW_ORIGIN_Z_ALIGNED, + + POINTWORLDTEXTORIENTATION__TOTAL +}; + class PointWorldText { public: PointWorldText(); - PointWorldText(const char* pszText, Vector pos, CMaterialReference* font); + PointWorldText(char* pszText, Vector pos, CMaterialReference* font); ~PointWorldText(); - int DrawModel(float alpha = 1.0f); + void DrawModel(); + void SetAbsOrigin(Vector origin) { m_vecAbsOrigin = origin; }; void SetText(const char* pszText); + void SetAlpha(const float alpha) { m_colTextColor.a = alpha; }; + void SetTextSize(const float size) { m_flTextSize = size; UpdateTextWorldSize(); }; + void SetTextSpacingX(const float spacing) { m_flTextSpacingX = spacing; UpdateTextWorldSize(); }; + void SetOrientation(const PointWorldTextOrientation orientation) { m_nOrientation = orientation; }; Vector GetAbsOrigin() { return m_vecAbsOrigin; } QAngle GetAbsAngles() { return m_vecAbsAngles; } @@ -28,14 +45,14 @@ class PointWorldText Vector m_vecAbsOrigin = {0, 0, 0}; QAngle m_vecAbsAngles = {0, 0, 0}; - char m_szText[ MAX_PLACE_NAME_LENGTH ]; float m_flTextSize = 64.f; float m_flTextSpacingX = 0.f; float m_flTextSpacingY = 0.f; - color32 m_colTextColor = {255, 255, 255, 255}; - int m_nOrientation = 3; + color32 m_colTextColor = {(byte)COLOR_NEO_WHITE.r(), (byte)COLOR_NEO_WHITE.g(), (byte)COLOR_NEO_WHITE.b(), (byte)COLOR_NEO_WHITE.a()}; + PointWorldTextOrientation m_nOrientation = POINTWORLDTEXTORIENTATION_VIEW_ORIGIN_Z_ALIGNED; + + char m_szText[ MAX_PLACE_NAME_LENGTH ]; int m_nTextLength = 0; - float m_flTextWorldWidth = 0.f; float m_flTextWorldHeight = 0.f; diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp index a67235e8f..93fedea47 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.cpp +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -5,6 +5,8 @@ #include "c_neo_player.h" #include "view.h" #include "tier1/lzmaDecoder.h" +#include "smoke_fog_overlay.h" +#include "nav_shared.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -15,26 +17,16 @@ NEO_HUD_ELEMENT_DECLARE_FREQ_CVAR(PlaceName, 0.1) static CNEOHud_PlaceName *g_PlaceName = nullptr; -ConVar cl_neo_hud_place_names_depth_test("cl_neo_hud_place_names_depth_test", "0", FCVAR_ARCHIVE, "Depth test in-world nearby place names", true, 0.0f, true, 1.0f, - [](IConVar* var, const char* pOldValue, float flOldValue)->void{ - if (!g_PlaceName) - return; - - IMaterial* textMaterial = g_PlaceName->GetFont(); - if (!textMaterial) - return; +static const char* TEXT_MATERIAL = "vgui/callout_text"; - textMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, !cl_neo_hud_place_names_depth_test.GetBool() ); -}); - -const char* TEXT_MATERIAL = "editor/worldtext_9"; CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent) : CHudElement(pElementName), Panel(parent, pElementName) { SetAutoDelete(true); m_iHideHudElementNumber = NEO_HUD_ELEMENT_PLACE_NAME; - if (parent) { + if (parent) + { SetParent(parent); } else @@ -114,24 +106,14 @@ void CNEOHud_PlaceName::UpdateStateForNeoHudElementDraw() } } -ConVar cl_neo_hud_curent_place_name_draw("cl_neo_hud_curent_place_name_draw", "1", FCVAR_ARCHIVE, "Draw the current place name", true, 0.0f, true, 1.0f); - -static bool shouldDrawPlaceNames = false; -static ConCommand startshowplacenames("+showplacenames", [](const CCommand& args)->void {shouldDrawPlaceNames = true; }); -static ConCommand endshowplacenames("-showplacenames", [](const CCommand& args)->void {shouldDrawPlaceNames = false; }); - -static float placeNamesRadiusSquared = 0.0f; -ConVar cl_neo_hud_place_names_radius("cl_neo_hud_place_names_radius", "2048", FCVAR_ARCHIVE, "Radius from the camera within which to draw the names of all nearby places", true, 0.0f, false, 0.0f, - [](IConVar* var, const char* pOldValue, float flOldValue)->void{ - placeNamesRadiusSquared = pow(cl_neo_hud_place_names_radius.GetFloat(), 2); -}); +ConVar cl_neo_hud_current_place_name_draw("cl_neo_hud_current_place_name_draw", "1", FCVAR_ARCHIVE, "Draw the current place name", true, 0.0f, true, 1.0f); void CNEOHud_PlaceName::DrawNeoHudElement() { if (!ShouldDraw()) return; - if (cl_neo_hud_curent_place_name_draw.GetBool()) + if (cl_neo_hud_current_place_name_draw.GetBool()) { vgui::surface()->DrawSetTextFont(textFont); vgui::surface()->DrawSetTextColor(textColor); @@ -146,46 +128,113 @@ void CNEOHud_PlaceName::Paint() PaintNeoElement(); } -static float placeNameAlpha = 0.f; +static bool shouldDrawPlaceNames = false; +static ConCommand startshowplacenames("+showPlaceNames", [](const CCommand& args)->void {shouldDrawPlaceNames = true; }); +static ConCommand endshowplacenames("-showPlaceNames", [](const CCommand& args)->void {shouldDrawPlaceNames = false; }); + +static float placeNameRadiusSquared = 0.0f; +ConVar cl_neo_hud_place_name_radius("cl_neo_hud_place_name_radius", "1024", FCVAR_ARCHIVE, "Radius from the camera within which to draw the names of all nearby places", true, 0.0f, false, 0.0f, + [](IConVar* var, const char* pOldValue, float flOldValue)->void{ + placeNameRadiusSquared = pow(cl_neo_hud_place_name_radius.GetFloat(), 2); +}); + +static float animationAlpha = 0.f; void CNEOHud_PlaceName::DrawPlaceNames() { constexpr int ANIMATION_SPEED = 2; - if (shouldDrawPlaceNames) + animationAlpha = shouldDrawPlaceNames ? min(1.0f, animationAlpha + (gpGlobals->frametime * ANIMATION_SPEED)) + : max(0.0f, animationAlpha - (gpGlobals->frametime * ANIMATION_SPEED)); + + for (PlaceNameCallout place : places) { - placeNameAlpha = min(1.0f, placeNameAlpha + (gpGlobals->frametime * ANIMATION_SPEED)); + if (place.navAreaCount <= 0) + { + continue; + } + + float alpha = animationAlpha; + if (placeNameRadiusSquared != 0) + { + if (const float distanceSquared = MainViewOrigin().DistToSqr(place.pointWorldText.GetAbsOrigin()); + distanceSquared > placeNameRadiusSquared) + { + alpha *= 1.f - min(1.f, ((distanceSquared - placeNameRadiusSquared) / placeNameRadiusSquared)); + } + } + + alpha -= g_SmokeFogOverlayAlpha; + alpha = clamp(alpha, 0.f, 1.f); + + place.pointWorldText.SetAlpha(255 * alpha); + place.pointWorldText.DrawModel(); } - else +} + +ConVar cl_neo_hud_place_name_text_size("cl_neo_hud_place_name_text_size", "32", FCVAR_ARCHIVE, "Place name text size", true, 1.f, false, 0.f, + [](IConVar* var, const char* pOldValue, float flOldValue)->void{ + if (g_PlaceName) + { + g_PlaceName->SetPlaceNameTextSize(cl_neo_hud_place_name_text_size.GetFloat()); + } + +}); +void CNEOHud_PlaceName::SetPlaceNameTextSize(const float textSize) +{ + for (int i=0; iframetime * ANIMATION_SPEED)); + places[i].pointWorldText.SetTextSize(textSize); } - if (placeNameAlpha) - { - for (PointWorldText place : places) +} + +ConVar cl_neo_hud_place_name_text_spacing_x("cl_neo_hud_place_name_text_spacing_x", "-8", FCVAR_ARCHIVE, "Place name spacing between characters", false, 0.f, false, 0.f, + [](IConVar* var, const char* pOldValue, float flOldValue)->void{ + if (g_PlaceName) { - float alpha = placeNameAlpha; - const float distanceSquared = MainViewOrigin().DistToSqr(place.GetAbsOrigin()); - if (distanceSquared > placeNamesRadiusSquared) - { - alpha *= 1.f - min(1.f, ((distanceSquared - placeNamesRadiusSquared) / placeNamesRadiusSquared)); - } + g_PlaceName->SetPlaceNameTextSpacingX(cl_neo_hud_place_name_text_spacing_x.GetFloat()); + } - place.DrawModel(alpha); +}); +void CNEOHud_PlaceName::SetPlaceNameTextSpacingX(const float textSpacingX) +{ + for (int i=0; ivoid{ + if (g_PlaceName) + { + g_PlaceName->SetPlaceNameOffset(cl_neo_hud_place_name_offset.GetFloat()); } + +}); +void CNEOHud_PlaceName::SetPlaceNameOffset(const float offset) +{ + const Vector vOffset = Vector(0, 0, offset); + for (int i=0; ivoid{ + if (g_PlaceName) + { + g_PlaceName->SetPlaceNameOrientation((PointWorldTextOrientation)cl_neo_hud_place_name_orientation.GetInt()); + } + +}); +void CNEOHud_PlaceName::SetPlaceNameOrientation(const PointWorldTextOrientation orientation) +{ + for (int i=0; i= 4) if ( version >= 14 ) { fileBuffer.GetUnsignedChar(); // skip m_isAnalyzed @@ -292,24 +335,178 @@ void CNEOHud_PlaceName::GetPlacesFromNavFile() { // read number of entries - IndexType count = fileBuffer.GetUnsignedShort(); + unsigned short placeCount = fileBuffer.GetUnsignedShort(); places.RemoveAll(); // read each entry char placeName[256]; unsigned short len; - for( int i=0; i 11) + { + fileBuffer.GetUnsignedChar(); // Skip has unnamed areas + } + } + + // get number of areas + unsigned int areaCount = fileBuffer.GetUnsignedInt(); + unsigned int i; + + if (areaCount == 0) + { + return; + } + + // Read each nav area + for (i = 0; i < areaCount; ++i) + { + fileBuffer.GetUnsignedInt(); // Skip ID + + if (version <= 8) // Skip attribute flags + { + fileBuffer.GetUnsignedChar(); + } + else if (version < 13) + { + fileBuffer.GetUnsignedShort(); + } + else + { + fileBuffer.GetUnsignedInt(); + } + + Vector nwCorner; + Vector seCorner; + fileBuffer.Get(&nwCorner, 3 * sizeof(float)); + fileBuffer.Get(&seCorner, 3 * sizeof(float)); + + fileBuffer.GetFloat(); // Skip heights of implicit corners + fileBuffer.GetFloat(); + + for (int d = 0; d < NavDirType::NUM_DIRECTIONS; d++) + { + unsigned int connectionCount = fileBuffer.GetUnsignedInt(); + Assert(fileBuffer.IsValid()); + + for (unsigned int j = 0; j < connectionCount; ++j) + { + fileBuffer.GetUnsignedInt(); // Skip connection ID + Assert(fileBuffer.IsValid()); + } + } + + unsigned char hidingSpotCount = fileBuffer.GetUnsignedChar(); + for (unsigned char h = 0; h < hidingSpotCount; ++h) + { + fileBuffer.GetUnsignedInt(); // Skip hiding spot ID + fileBuffer.GetFloat(); // Skip hiding spot pos X + fileBuffer.GetFloat(); // Skip hiding spot pos Y + fileBuffer.GetFloat(); // Skip hiding spot pos Z + fileBuffer.GetUnsignedChar(); // Skip hiding spot flags + } + + if (version < 15) + { + // Skip the approach areas + unsigned char nToEat = fileBuffer.GetUnsignedChar(); + for (unsigned char a = 0; a < nToEat; ++a) + { + fileBuffer.GetUnsignedInt(); + fileBuffer.GetUnsignedInt(); + fileBuffer.GetUnsignedChar(); + fileBuffer.GetUnsignedInt(); + fileBuffer.GetUnsignedChar(); + } + } + + // Skip encounter paths + unsigned int encounterCount = fileBuffer.GetUnsignedInt(); + for (unsigned int e = 0; e < encounterCount; ++e) + { + fileBuffer.GetUnsignedInt(); // Skip from ID + fileBuffer.GetUnsignedChar(); // Skip from dir + fileBuffer.GetUnsignedInt(); // Skip to ID + fileBuffer.GetUnsignedChar(); // Skip to dir + + unsigned char spotCount = fileBuffer.GetUnsignedChar(); + for(unsigned char s=0; s 0 && entry <= places.Count()) + { + entry -= 1; + Vector newNavCenter = (nwCorner + seCorner) / 2.f; + places[entry].origin = ((places[entry].origin * places[entry].navAreaCount) + newNavCenter) / ++places[entry].navAreaCount; + places[entry].pointWorldText.SetAbsOrigin(places[entry].origin + Vector(0, 0, cl_neo_hud_place_name_offset.GetFloat())); + } + + if (version < 7) + { + continue; + } + + // Skip ladder data + for (int dir=0; dir places; + CUtlVector places; CMaterialReference m_Font; CPanelAnimationVarAliasType(int, textXpos, "textXpos", "80", "proportional_xpos"); diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index 97cb83b32..b7df5e001 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -2257,10 +2257,6 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int RenderPlayerSprites(); -#ifdef NEO - RenderPlaceNames(); -#endif // NEO - // Image-space motion blur if ( !building_cubemaps.GetBool() && viewRender.m_bDoBloomAndToneMapping ) // We probably should use a different view. variable here { @@ -2354,6 +2350,7 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int #ifdef NEO // && defined GLOWS_ENABLE? // Add glow effect after HDR stuff is done and vision modes are applied, so the colour of the effect doesn't vary GetClientModeNormal()->DoPostScreenSpaceEffects(&viewRender); + RenderPlaceNames(); #endif // NEO CleanupMain3DView( viewRender ); diff --git a/src/game/server/CMakeLists.txt b/src/game/server/CMakeLists.txt index a05ccbb8a..bc5a57683 100644 --- a/src/game/server/CMakeLists.txt +++ b/src/game/server/CMakeLists.txt @@ -1471,6 +1471,7 @@ target_sources_grouped( NAME "NEO" FILES ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/nav_shared.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_juggernaut.h diff --git a/src/game/server/nav.h b/src/game/server/nav.h index 78dcd7725..35899935e 100644 --- a/src/game/server/nav.h +++ b/src/game/server/nav.h @@ -14,6 +14,9 @@ #include "modelentities.h" // for CFuncBrush #include "doors.h" +#ifdef NEO +#include "nav_shared.h" +#endif // NEO /** * Below are several constants used by the navigation system. @@ -60,8 +63,9 @@ const float CliffHeight = 300.0f; // height which we consider a significant c #define HumanCrouchHeight 55 #define HumanCrouchEyeHeight 37 - +#ifndef NEO #define NAV_MAGIC_NUMBER 0xFEEDFACE // to help identify nav files +#endif // NEO /** * A place is a named group of navigation areas @@ -111,6 +115,7 @@ enum NavAttributeType extern NavAttributeType NameToNavAttribute( const char *name ); +#ifndef NEO enum NavDirType { NORTH = 0, @@ -120,6 +125,7 @@ enum NavDirType NUM_DIRECTIONS }; +#endif // NEO /** * Defines possible ways to move from one area to another @@ -141,6 +147,7 @@ enum NavTraverseType NUM_TRAVERSE_TYPES }; +#ifndef NEO enum NavCornerType { NORTH_WEST = 0, @@ -150,6 +157,7 @@ enum NavCornerType NUM_CORNERS }; +#endif // NEO enum NavRelativeDirType { diff --git a/src/game/server/nav_area.cpp b/src/game/server/nav_area.cpp index 4050b9f79..fe4deeb3e 100644 --- a/src/game/server/nav_area.cpp +++ b/src/game/server/nav_area.cpp @@ -35,6 +35,10 @@ #include "team.h" #include "nav_entities.h" +#ifdef NEO +#include "nav_shared.h" +#endif // NEO + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/src/game/server/nav_area.h b/src/game/server/nav_area.h index 69d51465f..cc631c6ee 100644 --- a/src/game/server/nav_area.h +++ b/src/game/server/nav_area.h @@ -15,8 +15,12 @@ #include "nav_ladder.h" #include "tier1/memstack.h" +#ifdef NEO +#include "nav_shared.h" +#else // BOTPORT: Clean up relationship between team index and danger storage in nav areas enum { MAX_NAV_TEAMS = 2 }; +#endif // NEO #define DebuggerBreakOnNaN_StagingOnly( _val ) diff --git a/src/game/server/nav_file.cpp b/src/game/server/nav_file.cpp index ab38e4479..66f74633c 100644 --- a/src/game/server/nav_file.cpp +++ b/src/game/server/nav_file.cpp @@ -34,19 +34,21 @@ #include "util_shared.h" +#ifdef NEO +#include "nav_shared.h" +#endif // NEO + // NOTE: This has to be the last file included! #include "tier0/memdbgon.h" +#ifndef NEO //-------------------------------------------------------------------------------------------------------------- /// The current version of the nav file format /// IMPORTANT: If this version changes, the swap function in makegamedata /// must be updated to match. If not, this will break the Xbox 360. // TODO: Was changed from 15, update when latest 360 code is integrated (MSB 5/5/09) -#ifdef NEO -const int NavCurrentVersion = 17; // Version 17 Places now store average origin -#else const int NavCurrentVersion = 16; #endif // NEO @@ -146,10 +148,6 @@ void PlaceDirectory::Save( CUtlBuffer &fileBuffer ) unsigned short len = (unsigned short)(strlen( placeName ) + 1); fileBuffer.PutUnsignedShort( len ); fileBuffer.Put( placeName, len ); -#ifdef NEO - Vector averageOrigin = TheNavMesh->PlaceToLocation(m_directory[i]); - fileBuffer.Put(&averageOrigin, 3 * sizeof(float)); -#endif // NEO } fileBuffer.PutUnsignedChar( m_hasUnnamedAreas ); @@ -170,11 +168,7 @@ void PlaceDirectory::Load( CUtlBuffer &fileBuffer, int version ) { len = fileBuffer.GetUnsignedShort(); fileBuffer.Get( placeName, MIN( sizeof( placeName ), len ) ); -#ifdef NEO - [[maybe_unused]] Vector averageOrigin; // origin will be recalculated when all the nav areas are loaded - fileBuffer.Get(&averageOrigin, 3 * sizeof(float)); TheNavMesh->LoadPlace(placeName); -#endif // NEO Place place = TheNavMesh->NameToPlace( placeName ); if (place == UNDEFINED_PLACE) { @@ -193,18 +187,16 @@ void PlaceDirectory::Load( CUtlBuffer &fileBuffer, int version ) PlaceDirectory placeDirectory; +#ifndef NEO #if defined( _X360 ) #define FORMAT_BSPFILE "maps\\%s.360.bsp" #define FORMAT_NAVFILE "maps\\%s.360.nav" #else #define FORMAT_BSPFILE "maps\\%s.bsp" -#ifdef NEO - #define FORMAT_NAVFILE "maps\\nav\\%s.nav" -#else #define FORMAT_NAVFILE "maps\\%s.nav" -#endif // NEO #define PATH_NAVFILE_EMBEDDED "maps\\embed.nav" #endif +#endif // NEO //-------------------------------------------------------------------------------------------------------------- /** diff --git a/src/game/shared/neo/nav_file_shared.cpp b/src/game/shared/neo/nav_file_shared.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/game/shared/neo/nav_file_shared.h b/src/game/shared/neo/nav_file_shared.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/game/shared/neo/nav_shared.h b/src/game/shared/neo/nav_shared.h new file mode 100644 index 000000000..25f87b27b --- /dev/null +++ b/src/game/shared/neo/nav_shared.h @@ -0,0 +1,57 @@ +#pragma once + +#if defined( _X360 ) + #define FORMAT_BSPFILE "maps\\%s.360.bsp" + #define FORMAT_NAVFILE "maps\\%s.360.nav" +#else + #define FORMAT_BSPFILE "maps\\%s.bsp" +#ifdef NEO + #define FORMAT_NAVFILE "maps\\nav\\%s.nav" +#else + #define FORMAT_NAVFILE "maps\\%s.nav" +#endif // NEO + #define PATH_NAVFILE_EMBEDDED "maps\\embed.nav" +#endif + +#define NAV_MAGIC_NUMBER 0xFEEDFACE // to help identify nav files + +//-------------------------------------------------------------------------------------------------------------- +/// The current version of the nav file format + +/// IMPORTANT: If this version changes, the swap function in makegamedata +/// must be updated to match. If not, this will break the Xbox 360. +// TODO: Was changed from 15, update when latest 360 code is integrated (MSB 5/5/09) +const int NavCurrentVersion = 16; + +enum NavDirType +{ + NORTH = 0, + EAST = 1, + SOUTH = 2, + WEST = 3, + + NUM_DIRECTIONS +}; + +enum { MAX_NAV_TEAMS = 2 }; + +enum NavCornerType +{ + NORTH_WEST = 0, + NORTH_EAST = 1, + SOUTH_EAST = 2, + SOUTH_WEST = 3, + + NUM_CORNERS +}; + +#ifdef CLIENT_DLL +// defined in CNavLadder +enum LadderDirectionType +{ + LADDER_UP = 0, + LADDER_DOWN, + + NUM_LADDER_DIRECTIONS +}; +#endif // CLIENT_DLL \ No newline at end of file From 638e281492b13fcba13860a15be9c404d6217a3e Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Fri, 28 Aug 2026 20:56:05 +0100 Subject: [PATCH 07/14] Add an option to the keybinds menu --- game/neo/scripts/kb_act.lst | 1 + 1 file changed, 1 insertion(+) diff --git a/game/neo/scripts/kb_act.lst b/game/neo/scripts/kb_act.lst index 966a3d43e..ce5ca00ee 100644 --- a/game/neo/scripts/kb_act.lst +++ b/game/neo/scripts/kb_act.lst @@ -48,6 +48,7 @@ "messagemode" "#Valve_Chat_Message" "messagemode2" "#Valve_Team_Message" "+attack3" "Ping Location" +"+showplacenames" "Show Nearby Place Names" "joinstar 0" "Join Alpha Star" "joinstar 1" "Join Bravo Star" "joinstar 2" "Join Charlie Star" From f982b06f28f6204d16da45354eedb4e273c7654f Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Fri, 28 Aug 2026 21:05:35 +0100 Subject: [PATCH 08/14] missing NEO guard --- src/game/server/nav_file.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/game/server/nav_file.cpp b/src/game/server/nav_file.cpp index 66f74633c..3a46fec00 100644 --- a/src/game/server/nav_file.cpp +++ b/src/game/server/nav_file.cpp @@ -168,7 +168,9 @@ void PlaceDirectory::Load( CUtlBuffer &fileBuffer, int version ) { len = fileBuffer.GetUnsignedShort(); fileBuffer.Get( placeName, MIN( sizeof( placeName ), len ) ); +#ifdef NEO TheNavMesh->LoadPlace(placeName); +#endif // NEO Place place = TheNavMesh->NameToPlace( placeName ); if (place == UNDEFINED_PLACE) { From 1ae24a79dab129ad349cca3bcd02a524f3c3a49d Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Fri, 28 Aug 2026 21:28:07 +0100 Subject: [PATCH 09/14] fix compiling with unity build disabled, radius not updating on initial game launch --- src/game/client/neo/c_neo_point_world_text.cpp | 1 + src/game/client/neo/ui/neo_hud_place_name.cpp | 18 ++++++++++++------ src/game/server/nav_mesh.cpp | 16 ++++++++-------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp index b89102eb4..7b171394d 100644 --- a/src/game/client/neo/c_neo_point_world_text.cpp +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -1,4 +1,5 @@ #include "c_neo_point_world_text.h" +#include "view_scene.h" #include "view.h" typedef struct Character { diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp index 93fedea47..2d78803a0 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.cpp +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -7,6 +7,7 @@ #include "tier1/lzmaDecoder.h" #include "smoke_fog_overlay.h" #include "nav_shared.h" +#include "filesystem.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -19,6 +20,15 @@ static CNEOHud_PlaceName *g_PlaceName = nullptr; static const char* TEXT_MATERIAL = "vgui/callout_text"; +static float placeNameRadiusSquared = 0.f; +extern ConVar cl_neo_hud_place_name_radius; +void placeNameRadiusChangeCallback(IConVar* var = nullptr, const char* pOldValue = nullptr, float flOldValue = 0.f) +{ + placeNameRadiusSquared = pow(cl_neo_hud_place_name_radius.GetFloat(), 2); +} +ConVar cl_neo_hud_place_name_radius("cl_neo_hud_place_name_radius", "1024", FCVAR_ARCHIVE, "Radius from the camera within which to draw the names of all nearby places", true, 0.0f, false, 0.0f, + placeNameRadiusChangeCallback); + CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *parent) : CHudElement(pElementName), Panel(parent, pElementName) { @@ -41,6 +51,8 @@ CNEOHud_PlaceName::CNEOHud_PlaceName(const char *pElementName, vgui::Panel *pare PrecacheMaterial( TEXT_MATERIAL ); m_Font.Init(TEXT_MATERIAL, TEXTURE_GROUP_PRECACHED, true); + + placeNameRadiusChangeCallback(); } CNEOHud_PlaceName::~CNEOHud_PlaceName() @@ -132,12 +144,6 @@ static bool shouldDrawPlaceNames = false; static ConCommand startshowplacenames("+showPlaceNames", [](const CCommand& args)->void {shouldDrawPlaceNames = true; }); static ConCommand endshowplacenames("-showPlaceNames", [](const CCommand& args)->void {shouldDrawPlaceNames = false; }); -static float placeNameRadiusSquared = 0.0f; -ConVar cl_neo_hud_place_name_radius("cl_neo_hud_place_name_radius", "1024", FCVAR_ARCHIVE, "Radius from the camera within which to draw the names of all nearby places", true, 0.0f, false, 0.0f, - [](IConVar* var, const char* pOldValue, float flOldValue)->void{ - placeNameRadiusSquared = pow(cl_neo_hud_place_name_radius.GetFloat(), 2); -}); - static float animationAlpha = 0.f; void CNEOHud_PlaceName::DrawPlaceNames() { diff --git a/src/game/server/nav_mesh.cpp b/src/game/server/nav_mesh.cpp index 4cea3bb92..2a74a6be5 100644 --- a/src/game/server/nav_mesh.cpp +++ b/src/game/server/nav_mesh.cpp @@ -1213,7 +1213,7 @@ void CNavMesh::LoadPlaceDatabase( void ) const char *CNavMesh::PlaceToName( Place place ) const { #ifdef NEO - if (place >= 1 && place <= m_placeName.Count()) + if (place >= 1 && place <= (Place)m_placeName.Count()) return m_placeName[ (int)place - 1 ].name; #else if (place >= 1 && place <= m_placeCount) @@ -1232,7 +1232,7 @@ const char *CNavMesh::PlaceToName( Place place ) const Place CNavMesh::NameToPlace( const char *name ) const { #ifdef NEO - for( unsigned int i=0; i= 1 && place <= m_placeName.Count()) + if (place >= 1 && place <= (Place)m_placeName.Count()) return m_placeName[ (int)place - 1 ].averageCenter; return vec3_origin; @@ -1352,7 +1352,7 @@ Place CNavMesh::NextAvailablePlace(const char* name) void CNavMesh::IncrementNumPlaces(Place place, CNavArea* area) { - if (place <= UNDEFINED_PLACE || place > m_placeName.Count()) + if (place <= UNDEFINED_PLACE || place > (Place)m_placeName.Count()) { return; } @@ -1372,7 +1372,7 @@ void CNavMesh::IncrementNumPlaces(Place place, CNavArea* area) void CNavMesh::DecrementNumPlaces(Place place, CNavArea* area) { - if (place <= UNDEFINED_PLACE || place > m_placeName.Count()) + if (place <= UNDEFINED_PLACE || place > (Place)m_placeName.Count()) { return; } @@ -1402,7 +1402,7 @@ int CNavMesh::PlaceNameAutocomplete( char const *partial, char commands[ COMMAND int partialLength = Q_strlen( partial ); #ifdef NEO - for( unsigned int i=0; i placeNames; #ifdef NEO - for ( i=0; i Date: Sat, 29 Aug 2026 06:21:14 +0000 Subject: [PATCH 10/14] Update src/game/client/neo/c_neo_point_world_text.cpp set text length after copy Co-authored-by: Dan Peavey --- src/game/client/neo/c_neo_point_world_text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp index 7b171394d..d8527974a 100644 --- a/src/game/client/neo/c_neo_point_world_text.cpp +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -130,8 +130,8 @@ PointWorldText::~PointWorldText() void PointWorldText::SetText( const char* pszText ) { - m_nTextLength = V_strlen( pszText ); V_strncpy( m_szText, pszText, sizeof(m_szText) ); + m_nTextLength = V_strlen( m_szText ); UpdateTextWorldSize(); } From 9bb947dfe43a50c9d2ae42f514b5d8fb9a32373f Mon Sep 17 00:00:00 2001 From: Adam <44210793+AdamTadeusz@users.noreply.github.com> Date: Sat, 29 Aug 2026 06:21:34 +0000 Subject: [PATCH 11/14] Update src/game/server/nav_area.cpp Update place nav area counts Co-authored-by: Dan Peavey --- src/game/server/nav_area.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/server/nav_area.cpp b/src/game/server/nav_area.cpp index fe4deeb3e..e5e33113c 100644 --- a/src/game/server/nav_area.cpp +++ b/src/game/server/nav_area.cpp @@ -1271,8 +1271,8 @@ bool CNavArea::SplitEdit( bool splitAlongX, float splitEdge, CNavArea **outAlpha #ifdef NEO // If the old area had a place name, the new areas will inherit it - alpha->m_place = m_place; - beta->m_place = m_place; + alpha->SetPlace( m_place ); + beta->SetPlace( m_place ); #endif // NEO // return new areas From 8226fc42f667d3f0fc5310c9d8f28eff130c4e38 Mon Sep 17 00:00:00 2001 From: Adam <44210793+AdamTadeusz@users.noreply.github.com> Date: Sat, 29 Aug 2026 06:21:58 +0000 Subject: [PATCH 12/14] Update src/game/client/neo/c_neo_point_world_text.cpp remove incrementreferencecount Co-authored-by: Dan Peavey --- src/game/client/neo/c_neo_point_world_text.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp index d8527974a..4cf124e29 100644 --- a/src/game/client/neo/c_neo_point_world_text.cpp +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -266,7 +266,6 @@ void PointWorldText::DrawModel() CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); pRenderContext->Bind( pDebugText ); - pDebugText->IncrementReferenceCount(); IMesh* pMesh = pRenderContext->GetDynamicMesh(); CMeshBuilder meshBuilder; From 975d25d2cd80d0896614eade958be911600ce104 Mon Sep 17 00:00:00 2001 From: Adam <44210793+AdamTadeusz@users.noreply.github.com> Date: Sat, 29 Aug 2026 06:22:11 +0000 Subject: [PATCH 13/14] Update src/game/client/neo/c_neo_point_world_text.h pragma once Co-authored-by: Dan Peavey --- src/game/client/neo/c_neo_point_world_text.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/game/client/neo/c_neo_point_world_text.h b/src/game/client/neo/c_neo_point_world_text.h index 9b0206a6d..4e384b14a 100644 --- a/src/game/client/neo/c_neo_point_world_text.h +++ b/src/game/client/neo/c_neo_point_world_text.h @@ -1,3 +1,5 @@ +#pragma once + /////////////////////////////////////////////// // A non-networked non-entity PointWorldText // /////////////////////////////////////////////// From 8704807fd98c117482ae060a5a134157b1be59b5 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Sat, 29 Aug 2026 07:42:48 +0100 Subject: [PATCH 14/14] don't repeatedly update m_szLastPlaceName when an empty string, use wide and textXPos textYPos --- src/game/client/neo/c_neo_point_world_text.cpp | 1 - src/game/client/neo/ui/neo_hud_place_name.cpp | 4 ++-- src/game/server/neo/neo_player.cpp | 13 +++++-------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/game/client/neo/c_neo_point_world_text.cpp b/src/game/client/neo/c_neo_point_world_text.cpp index 7b171394d..9ef1a2c44 100644 --- a/src/game/client/neo/c_neo_point_world_text.cpp +++ b/src/game/client/neo/c_neo_point_world_text.cpp @@ -266,7 +266,6 @@ void PointWorldText::DrawModel() CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); pRenderContext->Bind( pDebugText ); - pDebugText->IncrementReferenceCount(); IMesh* pMesh = pRenderContext->GetDynamicMesh(); CMeshBuilder meshBuilder; diff --git a/src/game/client/neo/ui/neo_hud_place_name.cpp b/src/game/client/neo/ui/neo_hud_place_name.cpp index 2d78803a0..340dbb4e7 100644 --- a/src/game/client/neo/ui/neo_hud_place_name.cpp +++ b/src/game/client/neo/ui/neo_hud_place_name.cpp @@ -67,7 +67,7 @@ void CNEOHud_PlaceName::ApplySchemeSettings(vgui::IScheme* pScheme) { BaseClass::ApplySchemeSettings(pScheme); - int wide = 0, tall = 0; + int tall = 0; vgui::surface()->GetScreenSize(wide, tall); SetBounds(0, 0, wide, tall); @@ -129,7 +129,7 @@ void CNEOHud_PlaceName::DrawNeoHudElement() { vgui::surface()->DrawSetTextFont(textFont); vgui::surface()->DrawSetTextColor(textColor); - vgui::surface()->DrawSetTextPos(textXOffset, 0); + vgui::surface()->DrawSetTextPos(textXpos + textXOffset, textYpos); vgui::surface()->DrawPrintText(m_szPlaceName, V_wcslen(m_szPlaceName)); } } diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index 9d157fdad..e27818028 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -1196,17 +1196,14 @@ void CNEO_Player::PreThink(void) if (TheNavMesh) { - if (const char* placeName = TheNavMesh->PlaceToName(TheNavMesh->GetPlace(GetAbsOrigin())); - placeName && placeName[0]) + const char* placeName = TheNavMesh->PlaceToName(TheNavMesh->GetPlace(GetAbsOrigin())); + if (!placeName || !placeName[0]) { - if (Q_strcmp(m_szLastPlaceName.Get(), placeName)) - { - Q_strncpy(m_szLastPlaceName.GetForModify(), placeName, MAX_PLACE_NAME_LENGTH); - } + placeName = ""; } - else + if (Q_strcmp(m_szLastPlaceName.Get(), placeName)) { - Q_strncpy(m_szLastPlaceName.GetForModify(), "", MAX_PLACE_NAME_LENGTH); + Q_strncpy(m_szLastPlaceName.GetForModify(), placeName, sizeof(m_szLastPlaceName)); } } }