Skip to content

Commit

Permalink
feat: portals in trace
Browse files Browse the repository at this point in the history
  • Loading branch information
RainbowwPhoenixx authored and mlugg committed Jul 16, 2022
1 parent 69307fd commit d96c2db
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 1 deletion.
129 changes: 128 additions & 1 deletion src/Features/PlayerTrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Command.hpp"
#include "Event.hpp"
#include "Features/Camera.hpp"
#include "Features/EntityList.hpp"
#include "Features/OverlayRender.hpp"
#include "Features/Session.hpp"
#include "Features/Tas/TasPlayer.hpp"
Expand All @@ -24,7 +25,7 @@ Variable sar_trace_use_shot_eyeoffset("sar_trace_use_shot_eyeoffset", "1", 0, 1,

Variable sar_trace_draw("sar_trace_draw", "0", 0, 1, "Display the recorded player trace. Requires cheats\n");
Variable sar_trace_draw_through_walls("sar_trace_draw_through_walls", "1", "Display the player trace through walls. Requires sar_trace_draw\n");
Variable sar_trace_draw_speed_deltas("sar_trace_draw_speed_deltas", "1", "Display the speed deltas. Requires sar_trace_draw\n");
Variable sar_trace_draw_speed_deltas("sar_trace_draw_speed_deltas", "0", "Display the speed deltas. Requires sar_trace_draw\n");
Variable sar_trace_draw_time("sar_trace_draw_time", "3", 0, 3,
"Display tick above trace hover info\n"
"0 = hide tick info\n"
Expand All @@ -40,6 +41,9 @@ Variable sar_trace_bbox_ent_record("sar_trace_bbox_ent_record", "1", "Record hit
Variable sar_trace_bbox_ent_draw("sar_trace_bbox_ent_draw", "1", "Draw hitboxes of nearby entities in the trace.\n");
Variable sar_trace_bbox_ent_dist("sar_trace_bbox_ent_dist", "200", 50, "Distance from which to capture entity hitboxes.\n");

Variable sar_trace_portal_record("sar_trace_portal_record", "1", "Record portal locations.\n");
Variable sar_trace_portal_opacity("sar_trace_portal_opacity", "100", 0, 255, "Opacity of trace portal previews.\n");

Vector g_playerTraceTeleportLocation;
int g_playerTraceTeleportSlot;
bool g_playerTraceNeedsTeleport = false;
Expand Down Expand Up @@ -164,6 +168,12 @@ void PlayerTrace::AddPoint(std::string trace_name, void *player, int slot, bool
trace.grounded[slot].push_back(grounded);
trace.crouched[slot].push_back(ducked);
trace.hitboxes[slot].push_back(hitboxes);

// Only do it for one of the slots since we record all the portals in the map at once
if (slot == 0) {
PortalLocations portals = ConstructPortalLocations();
trace.portals.push_back(portals);
}
}
Trace *PlayerTrace::GetTrace(std::string trace_name) {
auto trace = traces.find(trace_name);
Expand Down Expand Up @@ -441,6 +451,91 @@ void PlayerTrace::DrawBboxAt(int tick) const {
}
}
}
void PlayerTrace::DrawPortalsAt(int tick) const {
if (engine->IsSkipping()) return;

for (const auto &[trace_idx, trace] : traces) {
if (trace.portals.size() == 0) continue;

unsigned localtick = tickUserToInternal(tick, trace);

// Clamp tick to the number of positions in the trace
if (trace.portals.size() <= localtick)
localtick = trace.portals.size()-1;

// Draw portals
Color blue { 111, 184, 255, 255 };
Color orange { 255, 184, 86, 255 };
Color atlas_prim { 32, 128, 210, 255 };
Color atlas_second { 16, 0, 210, 255 };
Color pbody_prim { 255, 180, 32, 255 };
Color pbody_second { 58, 3, 3, 255 };

auto drawPortal = [&](Color portalColor, Vector origin, QAngle angles) {
portalColor.a = (uint8_t)sar_trace_portal_opacity.GetInt();

// Bump portal by slightly more than DIST_EPSILON
Vector tmp;
Math::AngleVectors(angles, &tmp);
origin = origin + tmp*0.04;

// Convert to radians!
double syaw = sin(angles.y * M_PI/180);
double cyaw = cos(angles.y * M_PI/180);
double spitch = sin(angles.x * M_PI/180);
double cpitch = cos(angles.x * M_PI/180);

// yaw+pitch rotation matrix
Matrix rot{3, 3, 0};
rot(0, 0) = cyaw * cpitch;
rot(0, 1) = -syaw;
rot(0, 2) = cyaw * spitch;
rot(1, 0) = syaw * cpitch;
rot(1, 1) = cyaw;
rot(1, 2) = syaw * spitch;
rot(2, 0) = -spitch;
rot(2, 1) = 0;
rot(2, 2) = cpitch;

MeshId mesh = OverlayRender::createMesh(RenderCallback::constant(portalColor), RenderCallback::none);

OverlayRender::addQuad(
mesh,
origin + rot * Vector{0, -32, -56},
origin + rot * Vector{0, -32, 56},
origin + rot * Vector{0, 32, 56},
origin + rot * Vector{0, 32, -56}
);

// Add a little tick on the top of the portal so we can compare
// orientations
OverlayRender::addTriangle(
mesh,
origin + rot * Vector{0, -5, 56},
origin + rot * Vector{0, 0, 64},
origin + rot * Vector{0, 5, 56}
);
};

for (auto portal : trace.portals[localtick].locations) {
Color color;
if (portal.is_coop) {
if (portal.is_atlas)
color = portal.is_primary? atlas_prim: atlas_second;
else
color = portal.is_primary? pbody_prim: pbody_second;
} else {
color = portal.is_primary? blue: orange;
}

drawPortal(
color,
portal.pos,
portal.ang
);
}
}
}

void PlayerTrace::TeleportAt(std::string trace_name, int slot, int tick, bool eye) {
if (traces.count(trace_name) == 0) {
Expand Down Expand Up @@ -553,6 +648,37 @@ HitboxList PlayerTrace::ConstructHitboxList(Vector center) const {
return list;
}

PortalLocations PlayerTrace::ConstructPortalLocations() const {
if (!sar_trace_portal_record.GetBool()) return PortalLocations{};

PortalLocations portals;

for (int i = 0; i < Offsets::NUM_ENT_ENTRIES; ++i) {
void *ent = server->m_EntPtrArray[i].m_pEntity;
if (!ent) continue;
if (server->IsPlayer(ent)) continue;
if (strcmp(server->GetEntityClassName(ent), "prop_portal")) continue;
if (!*(bool *)((uintptr_t)ent + Offsets::m_bActivated)) continue;

PortalLocations::PortalLocation portal;

portal.pos = server->GetAbsOrigin(ent);
portal.ang = server->GetAbsAngles(ent);
portal.is_primary = !*(bool *)((uintptr_t)ent + Offsets::m_bIsPortal2);
portal.is_coop = engine->IsCoop();

if (portal.is_coop) {
CBaseHandle shooter_handle = *(CBaseHandle *)((uintptr_t)ent + Offsets::m_hFiredByPlayer);
void *shooter = entityList->LookupEntity(shooter_handle);
portal.is_atlas = shooter == server->GetPlayer(1);
}

portals.locations.push_back(portal);
}

return portals;
}

ON_EVENT(PROCESS_MOVEMENT) {
// detect trace switch
playerTrace->CheckTraceChanged();
Expand Down Expand Up @@ -717,6 +843,7 @@ ON_EVENT(RENDER) {
int tick = sar_trace_bbox_at.GetInt();
if (tick != -1) {
playerTrace->DrawBboxAt(tick);
playerTrace->DrawPortalsAt(tick);
}

const Vector hud_offset = {0.0, 0.0, 10.0};
Expand Down
21 changes: 21 additions & 0 deletions src/Features/PlayerTrace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ struct HitboxList {
std::vector<ObbBox> obb;
};

struct PortalLocations {
struct PortalLocation {
Vector pos;
QAngle ang;
bool is_primary;
bool is_coop;
bool is_atlas;
};

// This should contain all portals, including
// partner ones.
std::vector<PortalLocation> locations;
};

struct Trace {
int startSessionTick;
int startTasTick;
Expand All @@ -32,6 +46,9 @@ struct Trace {
std::vector<bool> grounded[2];
std::vector<bool> crouched[2];
std::vector<HitboxList> hitboxes[2];
// Only have one of those, store all the portals in the map
// indiscriminately of player (also ones placed by pedestals etc)
std::vector<PortalLocations> portals;
};

class PlayerTrace : public Feature {
Expand Down Expand Up @@ -63,10 +80,14 @@ class PlayerTrace : public Feature {
void DrawSpeedDeltas() const;
// Display a bbox at the given tick
void DrawBboxAt(int tick) const;
// Display the portals at the given tick
void DrawPortalsAt(int tick) const;
// Teleport to given tick on given trace
void TeleportAt(std::string trace_name, int slot, int tick, bool eye);
// Construct a list of the hitboxes of all entities near a point
HitboxList ConstructHitboxList(Vector center) const;
// Construct a list of all portals in the map
PortalLocations ConstructPortalLocations() const;
// Draw info about all traces to a HUD context
void DrawTraceHud(HudContext *ctx);
// Corrects latest eye offset according to given CMoveData, to make it correct for portal shooting preview
Expand Down
1 change: 1 addition & 0 deletions src/Modules/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ bool Server::Init() {
offsetFinder->ServerSide("CPortal_Player", "iNumPortalsPlaced", &Offsets::iNumPortalsPlaced);
offsetFinder->ServerSide("CPortal_Player", "m_hActiveWeapon", &Offsets::m_hActiveWeapon);
offsetFinder->ServerSide("CProp_Portal", "m_bActivated", &Offsets::m_bActivated);
offsetFinder->ServerSide("CProp_Portal", "m_hFiredByPlayer", &Offsets::m_hFiredByPlayer);
offsetFinder->ServerSide("CProp_Portal", "m_bIsPortal2", &Offsets::m_bIsPortal2);
offsetFinder->ServerSide("CWeaponPortalgun", "m_bCanFirePortal1", &Offsets::m_bCanFirePortal1);
offsetFinder->ServerSide("CWeaponPortalgun", "m_bCanFirePortal2", &Offsets::m_bCanFirePortal2);
Expand Down
1 change: 1 addition & 0 deletions src/OffsetsData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ OFFSET_EMPTY(S_m_vForward)
OFFSET_DEFAULT(C_m_matrixThisToLinked, 3516, 3492)
OFFSET_DEFAULT(S_m_matrixThisToLinked, 1220, 1244)
OFFSET_EMPTY(C_m_hLinkedPortal)
OFFSET_EMPTY(m_hFiredByPlayer)

// IEngineVGuiInternal
OFFSET_DEFAULT(IsGameUIVisible, 2, 2)
Expand Down

0 comments on commit d96c2db

Please sign in to comment.