Skip to content

Commit

Permalink
Added PVS:DebugOverlay function
Browse files Browse the repository at this point in the history
Also relevant documentation.
  • Loading branch information
piqey committed Dec 20, 2023
1 parent 7242d53 commit 57314a7
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 10 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Contains the following metamethods:
### `boolean` PVS:CheckOrigin(`Vector` origin)
#### Description
Determines whether a given point exists within the PVS.
#### Parameters:
#### Parameters
| Name | Type | Description |
| :---: | :---: | :--- |
| `origin` | `Vector` | The position in the map to evaluate. |
Expand Down Expand Up @@ -157,7 +157,7 @@ Determines whether the given box is within the PVS at any point.
### `boolean` PVS:ContainsCluster(`number` cluster)
#### Description
Determines whether a particular cluster exists within the PVS.
#### Parameters:
#### Parameters
| Name | Type | Description |
| :---: | :---: | :--- |
| `cluster` | `number` | The ID of the cluster to search for. |
Expand All @@ -177,3 +177,20 @@ Determines whether a particular cluster exists within the PVS.
| Name | Type | Description |
| :---: | :---: | :--- |
| `total` | `number` | The total number of clusters accounted for by the PVS object's internal byte buffer (visibility notwithstanding). |

---

### `void` PVS:DebugOverlay(`Color` color, `number` duration)
#### Description
Shows colored boxes for a specified duration indicating the bounding boxes of each cluster visible with the PVS in question.
> [!IMPORTANT]
> In order to see anything, you must:
> * Set `developer` to `2` in the game console
> * Be the host of a listen server or singleplayer game
> [!TIP]
> Use transparent colors. A color alpha of `255` will produce completely opaque boxes, which are hardly conducive to an effective visual display. Try starting out with `40`.
#### Parameters
| Name | Type | Description |
| :---: | :---: | :--- |
| `color` | `Color` | The color the boxes should be drawn with. |
69 changes: 67 additions & 2 deletions src/Types/PVS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ namespace VisInfo::Types
return (buffer[cluster / 8] & (1 << (cluster % 8))) != 0;
}

void PVSData::DebugOverlay(int r, int g, int b, int a, float duration) const
{
bbox_t* bboxes = new bbox_t[total];

engine_server->GetAllClusterBounds(bboxes, total);

for (int i = 0; i < total; i++)
if (buffer[i / 8] & (1 << (i % 8)))
{
#pragma warning(suppress: 6385)
bbox_t& bbox = bboxes[i];
Vector center = 0.5f * (bbox.mins + bbox.maxs);

debug_overlay->AddBoxOverlay(center, bbox.mins - center, bbox.maxs - center, qZero, r, g, b, a, duration);
}

delete[] bboxes;
}

// Lua UserType stuff

LUA_FUNCTION_STATIC(index)
Expand Down Expand Up @@ -118,11 +137,11 @@ namespace VisInfo::Types
LUA_FUNCTION_STATIC(ContainsCluster)
{
LUA->CheckType(1, PVSData::meta);
LUA->CheckNumber(2);
int cluster = (int)LUA->CheckNumber(2);

PVSData* pvs = LUA->GetUserType<PVSData>(1, PVSData::meta);

try { LUA->PushBool(pvs->ContainsCluster((int)LUA->GetNumber(2))); }
try { LUA->PushBool(pvs->ContainsCluster(cluster)); }
catch (const std::runtime_error& e) { LUA->ThrowError(e.what()); }
catch (const std::out_of_range& e) { LUA->FormattedError("%s Use a number between %f and %f.", e.what(), 0.0, (double)(pvs->total - 1)); }

Expand All @@ -137,6 +156,49 @@ namespace VisInfo::Types
return 1;
}

LUA_FUNCTION_STATIC(DebugOverlay)
{
LUA->CheckType(1, PVSData::meta);
LUA->CheckType(2, GarrysMod::Lua::Type::Table);
float duration = (float)LUA->CheckNumber(3);

LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB); // Push _G onto the stack
LUA->GetField(-1, "IsColor"); // Push the IsColor function from _G onto the stack

LUA->Remove(-2); // Remove _G from the stack, keeping IsColor

LUA->Push(2); // Push the color table onto the stack

LUA->Call(1, 1); // Call IsColor with 1 argument, 1 result

if (!LUA->GetBool(-1))
LUA->ThrowError("Second argument must be a valid Color object!");

LUA->Pop(1); // Pop the IsColor bool result off the stack

LUA->Push(2); // Push the color table onto the stack

LUA->GetField(-1, "r");
int r = (int)LUA->GetNumber(-1);
LUA->Pop(1);

LUA->GetField(-1, "g");
int g = (int)LUA->GetNumber(-1);
LUA->Pop(1);

LUA->GetField(-1, "b");
int b = (int)LUA->GetNumber(-1);
LUA->Pop(1);

LUA->GetField(-1, "a");
int a = (int)LUA->GetNumber(-1);
LUA->Pop(2); // Also pop the color table off the stack

LUA->GetUserType<PVSData>(1, PVSData::meta)->DebugOverlay(r, g, b, a, duration);

return 0;
}

const char* PVSData::typeName = "PVS";
int PVSData::meta = 0;

Expand Down Expand Up @@ -165,6 +227,9 @@ namespace VisInfo::Types
L->PushCFunction(GetTotalClusters);
L->SetField(-2, "GetTotalClusters");

L->PushCFunction(VisInfo::Types::DebugOverlay);
L->SetField(-2, "DebugOverlay");

L->Pop();
}

Expand Down
6 changes: 6 additions & 0 deletions src/Types/PVS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
#include "GarrysMod/Lua/Interface.h"
#include "GarrysMod/FactoryLoader.hpp"
#include "eiface.h"
#include "engine/ivdebugoverlay.h"

extern IVEngineServer* engine_server;
extern IVDebugOverlay* debug_overlay;

const QAngle qZero; // I don't know why vec3_angle is unresolved

// extern inline void LuaPrint(GarrysMod::Lua::ILuaBase* L, char* msg);
// extern inline void LuaPrint(GarrysMod::Lua::ILuaBase* L, char* msg, int num);
Expand All @@ -28,6 +32,8 @@ namespace VisInfo::Types
bool CheckBox(Vector mins, Vector maxs) const;
bool ContainsCluster(int cluster) const;

void DebugOverlay(int r, int g, int b, int a, float duration) const;

// Lua UserType stuff

static const char* typeName;
Expand Down
16 changes: 10 additions & 6 deletions src/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ LUA_FUNCTION_STATIC(GetAllClusterBounds)

LUA_FUNCTION_STATIC(GetPVSForCluster)
{
LUA->CheckType(1, GarrysMod::Lua::Type::Number);
int cluster = (int)LUA->CheckNumber(1);

int size = (int)ceil(engine_server->GetClusterCount() / 8.0f);
int size = (int)ceil(0.125f * engine_server->GetClusterCount());
byte* buffer = new byte[size];

engine_server->GetPVSForCluster((int)LUA->GetNumber(1), size, buffer);
engine_server->GetPVSForCluster(cluster, size, buffer);

LUA->PushUserType(new PVSData(size, buffer), PVSData::meta);

Expand All @@ -79,21 +79,25 @@ LUA_FUNCTION_STATIC(GetArea)

LUA_FUNCTION_STATIC(CheckAreasConnected)
{
LUA->CheckType(1, GarrysMod::Lua::Type::Number);
LUA->CheckType(2, GarrysMod::Lua::Type::Number);
int area1 = (int)LUA->CheckNumber(1);
int area2 = (int)LUA->CheckNumber(2);

LUA->PushNumber((double)engine_server->CheckAreasConnected((int)LUA->GetNumber(1), (int)LUA->GetNumber(2)));
LUA->PushNumber((double)engine_server->CheckAreasConnected(area1, area2));

return 1;
}

GMOD_MODULE_OPEN()
{
engine_server = engine_loader.GetInterface<IVEngineServer>(INTERFACEVERSION_VENGINESERVER);
debug_overlay = engine_loader.GetInterface<IVDebugOverlay>(VDEBUG_OVERLAY_INTERFACE_VERSION);

if (engine_server == nullptr)
LUA->ThrowError("Failed to resolve server-side engine interface!");

if (engine_server == nullptr)
LUA->ThrowError("Failed to resolve debug overlay interface!");

PVSData::Initialize(LUA);

LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB);
Expand Down
3 changes: 3 additions & 0 deletions src/module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "GarrysMod/Lua/Interface.h"
#include "GarrysMod/FactoryLoader.hpp"
#include "eiface.h"
#include "engine/ivdebugoverlay.h"

#include "Types/PVS.hpp"

Expand All @@ -27,4 +28,6 @@ inline void LuaPrint(GarrysMod::Lua::ILuaBase* L, char* msg, int num)
}

const SourceSDK::FactoryLoader engine_loader("engine");

IVEngineServer* engine_server = nullptr;
IVDebugOverlay* debug_overlay = nullptr;

0 comments on commit 57314a7

Please sign in to comment.