Skip to content

Commit f831f55

Browse files
committed
Remove selected pixel
1 parent 95b9e54 commit f831f55

2 files changed

Lines changed: 105 additions & 139 deletions

File tree

spt/features/visualizations/monocle/mon_feature.hpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -241,27 +241,22 @@ class MonocleFeature : public FeatureWrapper<MonocleFeature>
241241
float zoom = 10.f;
242242
} tooltip;
243243

244-
// returns user selected pixel
245-
std::optional<WorkerPixel> DrawWorkerImage(const char* label, MonocleWorker& wd);
244+
void DrawWorkerImage(const char* label, MonocleWorker& wd);
246245

247-
struct UserPixelSel
246+
struct UserPixelSelect
248247
{
249248
WorkerPixel selectedPxl{};
250249
WorkerPixel imgSize{};
251-
mon::TeleportChainParams params;
250+
mon::TeleportChainParams params; // params.pp may not be valid
252251
mon::TeleportChainResult result;
253-
bool active = false;
252+
bool bluePlacedLast = false;
253+
bool dirty = true;
254254

255-
void Update(const MonocleWorker& wd, WorkerPixel pxl);
256-
void Draw();
257-
258-
void Clear()
259-
{
260-
active = false;
261-
}
255+
void Update(const MonocleWorker& wd, WorkerPixel pxl, bool bluePlacedLast_);
256+
void DrawInfo();
262257
};
263258

264-
UserPixelSel hoveredPxl, selectedPxl;
259+
UserPixelSelect hoveredPxl;
265260

266261
void OnTickSignal(bool);
267262

spt/features/visualizations/monocle/mon_imgui.cpp

Lines changed: 97 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
#include "mon_feature.hpp"
44

55
/*
6-
* TODO feedback from bill
7-
*
8-
help text for newlocation cmd - you have to actually name the portals
9-
10-
future:
11-
toggle for showing player outline within portal bounds
12-
set_name manually
6+
* TODO future features:
7+
* - toggle for showing where in the portal the player will fit
8+
* - make a version of the newlocation cmd which doesn't require the player to manually name the portals
9+
* - compare the monocle portal values to the game to auto-detect which portal is "placed last"
1310
*/
1411

1512
#ifdef SPT_MONOCLE_FEATURE
@@ -22,14 +19,15 @@ set_name manually
2219
#include "spt\features\tracing.hpp"
2320
#include "spt\features\visualizations\imgui\imgui_interface.hpp"
2421

22+
// dumb botched class for a setting which has custom options and an autodetect
2523
template<typename T, size_t N>
2624
class ComboWithAutoOpt
2725
{
2826
static_assert(N > 0);
2927

3028
std::string autoOptLabel;
3129
std::array<std::pair<T, const char*>, N> userOpts;
32-
int imguiOpt = 0;
30+
int imguiOpt = 0; // 0 is auto
3331
std::optional<T> lastUpdate;
3432
T lastGrabbedVal;
3533

@@ -144,6 +142,43 @@ struct ImGuiPersist
144142

145143
} imguiPersist;
146144

145+
void MonocleFeature::UserPixelSelect::Update(const MonocleWorker& wd, WorkerPixel pxl, bool bluePlacedLast_)
146+
{
147+
dirty = false;
148+
bluePlacedLast = bluePlacedLast_;
149+
selectedPxl = pxl;
150+
imgSize = wd.GetImageSize();
151+
params = wd.GetMonocleData()->paramsTemplate;
152+
params.record_flags = mon::TCRF_RECORD_ENTITY;
153+
params.n_max_teleports = MAX_EDICTS; // I think anything above this is guaranteed to crash
154+
wd.DoWorkForPixel(pxl, params, result);
155+
}
156+
157+
void MonocleFeature::UserPixelSelect::DrawInfo()
158+
{
159+
ImGui::Text("pixel: (%hu,%hu) / (%hu,%hu)", selectedPxl.x, selectedPxl.y, imgSize.x, imgSize.y);
160+
Assert((params.record_flags & mon::TCRF_RECORD_ENTITY) && !result.ents.empty());
161+
mon::Vector startCenter = result.ents[0].GetCenter();
162+
ImGui::Text("entity center: " V_FMT, V_UNP(startCenter));
163+
164+
if (result.max_tps_exceeded)
165+
{
166+
ImGui::Text("result: unknown (possible crash)", result.total_n_teleports);
167+
ImGui::Text("total teleports: unknown (more than %u)", params.n_max_teleports);
168+
ImGui::Text("end behind portal: N/A");
169+
}
170+
else
171+
{
172+
ImGui::Text("result: %d CUM teleport(s)", result.cum_teleports);
173+
ImGui::Text("total teleports: %u", result.total_n_teleports);
174+
std::optional<bool> endBehind = MonocleWorker::EndBehindPortal(params, result);
175+
if (endBehind.has_value())
176+
ImGui::Text("end behind portal: %s", *endBehind ? "true" : "false");
177+
else
178+
ImGui::Text("end behind portal: N/A");
179+
}
180+
}
181+
147182
// callbacks for imgui to disable/re-enable image interpolation for the zoomed in tooltip
148183
struct SamplerState
149184
{
@@ -182,43 +217,7 @@ struct SamplerState
182217
}
183218
};
184219

185-
void MonocleFeature::UserPixelSel::Update(const MonocleWorker& wd, WorkerPixel pxl)
186-
{
187-
active = true;
188-
selectedPxl = pxl;
189-
imgSize = wd.GetImageSize();
190-
params = wd.GetMonocleData()->paramsTemplate;
191-
params.record_flags = mon::TCRF_RECORD_ENTITY;
192-
params.n_max_teleports = MAX_EDICTS; // I think anything above this is guaranteed to crash
193-
wd.DoWorkForPixel(pxl, params, result);
194-
}
195-
196-
void MonocleFeature::UserPixelSel::Draw()
197-
{
198-
ImGui::Text("pixel: (%hu,%hu) / (%hu,%hu)", selectedPxl.x, selectedPxl.y, imgSize.x, imgSize.y);
199-
Assert((params.record_flags & mon::TCRF_RECORD_ENTITY) && !result.ents.empty());
200-
mon::Vector startCenter = result.ents[0].GetCenter();
201-
ImGui::Text("entity center: " V_FMT, V_UNP(startCenter));
202-
203-
if (result.max_tps_exceeded)
204-
{
205-
ImGui::Text("result: unknown (possible crash)", result.total_n_teleports);
206-
ImGui::Text("total teleports: unknown (more than %u)", params.n_max_teleports);
207-
ImGui::Text("end behind portal: N/A");
208-
}
209-
else
210-
{
211-
ImGui::Text("result: %d CUM teleport(s)", result.cum_teleports);
212-
ImGui::Text("total teleports: %u", result.total_n_teleports);
213-
std::optional<bool> endBehind = MonocleWorker::EndBehindPortal(params, result);
214-
if (endBehind.has_value())
215-
ImGui::Text("end behind portal: %s", *endBehind ? "true" : "false");
216-
else
217-
ImGui::Text("end behind portal: N/A");
218-
}
219-
}
220-
221-
std::optional<WorkerPixel> MonocleFeature::DrawWorkerImage(const char* label, MonocleWorker& wd)
220+
void MonocleFeature::DrawWorkerImage(const char* label, MonocleWorker& wd)
222221
{
223222
ImGui::PushID(label);
224223
ImGui::BeginGroup();
@@ -232,6 +231,13 @@ std::optional<WorkerPixel> MonocleFeature::DrawWorkerImage(const char* label, Mo
232231
ImGui::BeginDisabled(!md);
233232
if (ImGui::Button("Copy newlocation cmd"))
234233
ImGui::SetClipboardText(worker1->GetMonocleData()->pp.NewLocationCmd("; ").c_str());
234+
if (md)
235+
{
236+
ImGui::SetItemTooltip(
237+
"To use this command, you must manually name your portals 'blue' and 'orange'\n"
238+
"using e.g. 'picker', looking at the portal bubble, and using 'ent_setname blue'.",
239+
md->paramsTemplate.first_tp_from_blue);
240+
}
235241
imguiPersist.minImgWidth = (int)ImGui::GetItemRectSize().x;
236242
ImGui::EndDisabled();
237243

@@ -315,25 +321,59 @@ std::optional<WorkerPixel> MonocleFeature::DrawWorkerImage(const char* label, Mo
315321
// border
316322
dltt->AddRect(c0, c1, borderColor);
317323

318-
if (hoveredPxl.selectedPxl != pxlSelectCoord
319-
|| hoveredPxl.params.first_tp_from_blue != md->paramsTemplate.first_tp_from_blue)
324+
bool curBluePlacedLast =
325+
wd.GetMonocleData()->pp.order == mon::PlacementOrder::ORANGE_OPEN_BLUE_NEW_LOCATION;
326+
if (hoveredPxl.dirty || hoveredPxl.selectedPxl != pxlSelectCoord
327+
|| hoveredPxl.bluePlacedLast != curBluePlacedLast)
320328
{
321-
hoveredPxl.Update(wd, pxlSelectCoord);
329+
hoveredPxl.Update(wd, pxlSelectCoord, curBluePlacedLast);
322330
}
323331

324332
ImGui::SameLine();
325333
ImGui::BeginGroup();
326-
hoveredPxl.Draw();
334+
hoveredPxl.DrawInfo();
327335
ImGui::EndGroup();
328336

329-
ImGui::Text("Click to get more information about this point");
337+
ImGui::Text("Click to copy setpos cmd");
338+
339+
// warning message
340+
static std::string setposWarningMsg;
341+
setposWarningMsg.clear();
342+
if (!hoveredPxl.result.ent.is_player)
343+
setposWarningMsg += "- the simulation was run on a non-player entity\n";
344+
auto& combos = imguiPersist.combos;
345+
if (!combos.playerCrouched.LastGrabbedMatchesLastUpdate())
346+
{
347+
setposWarningMsg += combos.playerCrouched.GetLastUpdateVal() ? "- the player is crouched\n"
348+
: "- the player is not crouched\n";
349+
}
350+
if (!combos.mapOriginEmpty.LastGrabbedMatchesLastUpdate())
351+
{
352+
setposWarningMsg += combos.mapOriginEmpty.GetLastUpdateVal()
353+
? "- the map origin is a passable space\n"
354+
: "- the map origin is not a passable space\n";
355+
}
356+
if (!combos.monocleGameVersion.LastGrabbedMatchesLastUpdate())
357+
setposWarningMsg += "- the simulation was done with a different game version\n";
358+
if (!setposWarningMsg.empty())
359+
{
360+
ImGui::TextColored(SPT_IMGUI_WARN_COLOR_YELLOW,
361+
ICON_CI_WARNING " the setpos command may not work as expected because:");
362+
ImGui::Text("%.*s", setposWarningMsg.size() - 1, setposWarningMsg.c_str());
363+
}
364+
365+
if (clicked)
366+
{
367+
mon::Entity entInFront = hoveredPxl.result.ents[0].WithNewCenter(
368+
hoveredPxl.result.ents[0].GetCenter() + hoveredPxl.params.EntryPortal().f);
369+
std::string cmd = std::format("{}; spt_afterticks 10 \"{}\"",
370+
entInFront.SetPosCmd(),
371+
hoveredPxl.result.ents[0].SetPosCmd());
372+
ImGui::SetClipboardText(cmd.c_str());
373+
}
330374

331375
ImGui::EndTooltip();
332376
}
333-
else
334-
{
335-
hoveredPxl.Clear();
336-
}
337377

338378
if (hasTooltip)
339379
{
@@ -346,10 +386,6 @@ std::optional<WorkerPixel> MonocleFeature::DrawWorkerImage(const char* label, Mo
346386

347387
ImGui::EndGroup();
348388
ImGui::PopID();
349-
350-
if (clicked && md)
351-
return pxlSelectCoord;
352-
return std::nullopt;
353389
}
354390

355391
void MonocleFeature::ImGuiDrawImages()
@@ -372,17 +408,13 @@ void MonocleFeature::ImGuiDrawImages()
372408

373409
ImGui::BeginGroup();
374410

375-
auto newSelect = DrawWorkerImage("Blue placed last", *worker1);
376-
if (newSelect.has_value())
377-
selectedPxl.Update(*worker1, newSelect.value());
411+
DrawWorkerImage("Blue placed last", *worker1);
378412

379413
ImGui::SameLine();
380414
ImGui::Dummy(ImVec2(10, 0));
381415
ImGui::SameLine();
382416

383-
newSelect = DrawWorkerImage("Orange placed last", *worker2);
384-
if (newSelect.has_value())
385-
selectedPxl.Update(*worker2, newSelect.value());
417+
DrawWorkerImage("Orange placed last", *worker2);
386418

387419
ImGui::EndGroup();
388420
}
@@ -466,52 +498,6 @@ void MonocleFeature::ImGuiTabCallback()
466498
RestartWorkers(newEntryPortal);
467499

468500
ImGuiDrawImages();
469-
470-
if (selectedPxl.active)
471-
{
472-
ImGui::SeparatorText("Selected pixel");
473-
474-
selectedPxl.Draw();
475-
476-
auto& result = selectedPxl.result;
477-
if (ImGui::Button("Copy setpos cmd"))
478-
{
479-
mon::Entity entInFront = result.ents[0].WithNewCenter(result.ents[0].GetCenter()
480-
+ selectedPxl.params.EntryPortal().f);
481-
std::string cmd = std::format("{}; spt_afterticks 10 \"{}\"",
482-
entInFront.SetPosCmd(),
483-
result.ents[0].SetPosCmd());
484-
ImGui::SetClipboardText(cmd.c_str());
485-
}
486-
// warning message
487-
static std::string setposWarningMsg;
488-
setposWarningMsg.clear();
489-
if (!result.ent.is_player)
490-
setposWarningMsg += "- The simulation was run on a non-player entity.\n";
491-
auto& combos = imguiPersist.combos;
492-
if (!combos.playerCrouched.LastGrabbedMatchesLastUpdate())
493-
{
494-
setposWarningMsg += combos.playerCrouched.GetLastUpdateVal()
495-
? "- The player is crouched.\n"
496-
: "- The player is not crouched.\n";
497-
}
498-
if (!combos.mapOriginEmpty.LastGrabbedMatchesLastUpdate())
499-
{
500-
setposWarningMsg += combos.mapOriginEmpty.GetLastUpdateVal()
501-
? "- The map origin is a passable space.\n"
502-
: "- The map origin is not a passable space.\n";
503-
}
504-
if (!combos.monocleGameVersion.LastGrabbedMatchesLastUpdate())
505-
setposWarningMsg += "- The simulation was done with a different game version.\n";
506-
if (!setposWarningMsg.empty())
507-
{
508-
ImGui::SameLine();
509-
ImGui::TextColored(SPT_IMGUI_WARN_COLOR_RED, ICON_CI_WARNING);
510-
ImGui::SetItemTooltip("This command may not work as expected because:\n%.*s",
511-
setposWarningMsg.size() - 1,
512-
setposWarningMsg.c_str());
513-
}
514-
}
515501
}
516502

517503
bool MonocleFeature::ImGuiDrawSettings()
@@ -643,10 +629,6 @@ void MonocleFeature::RestartWorkers(const utils::PortalInfo* newEntryPortal)
643629
imguiPersist.combos.monocleGameVersion.Grab(),
644630
paramsTemplate);
645631
}
646-
else
647-
{
648-
selectedPxl.Clear();
649-
}
650632

651633
if (!worker1)
652634
worker1 = std::make_shared<MonocleWorker>();
@@ -656,16 +638,7 @@ void MonocleFeature::RestartWorkers(const utils::PortalInfo* newEntryPortal)
656638
worker1->RestartWork(std::move(newMonData1), {w, h});
657639
worker2->RestartWork(std::move(newMonData2), {w, h});
658640

659-
if (hasOpenPortals && selectedPxl.active && worker1)
660-
{
661-
// adjust user pixel selection so that it's in the same relative spot in the image
662-
WorkerPixel oldImgSize = worker1->GetImageSize();
663-
WorkerPixel oldPxlSelect = selectedPxl.selectedPxl;
664-
MonocleWorker& wm = selectedPxl.params.first_tp_from_blue ? *worker1 : *worker2;
665-
selectedPxl.Update(wm,
666-
{(uint16_t)((float)oldPxlSelect.x / oldImgSize.x * w),
667-
(uint16_t)((float)oldPxlSelect.y / oldImgSize.y * h)});
668-
}
641+
hoveredPxl.dirty = true;
669642
}
670643

671644
void MonocleFeature::OnTickSignal(bool)
@@ -716,8 +689,6 @@ void MonocleFeature::UnloadFeature()
716689
{
717690
worker1.reset();
718691
worker2.reset();
719-
selectedPxl.Clear();
720-
hoveredPxl.Clear();
721692
}
722693

723694
#endif

0 commit comments

Comments
 (0)