F4MP/tiltedcode/Code/client/Services/Debug/Views/ComponentView.cpp
Jous99 37b16f1547 code upload
codigo original de f4mp y tilted para referencias
2026-01-06 18:45:00 +01:00

202 lines
7 KiB
C++

#include <Components.h>
#include <World.h>
#include <imgui.h>
#include <inttypes.h>
#include <Services/DebugService.h>
#include <Systems/AnimationSystem.h>
#include <BSGraphics/BSGraphicsRenderer.h>
#include <Camera/PlayerCamera.h>
#include <Games/Skyrim/Forms/TESForm.h>
#include <Games/Skyrim/Interface/Menus/HUDMenuUtils.h>
#include <Games/Skyrim/NetImmerse/NiCamera.h>
#include <Games/Skyrim/TESObjectREFR.h>
#include <NetImmerse/NiCamera.h>
namespace
{
#if 0
constexpr float fFloatQuestMarkerMaxDistance = 2000.f;
constexpr float fFloatQuestMarkerMinDistance = 1000.f;
float CalculateFloatingQuestMarkerAlpha()
{
float v1 = fsqrt((__m128)LODWORD(this->fDistanceToPlayerSqr)).m128_f32[0] -
fFloatQuestMarkerMaxDistance) /
(fFloatQuestMarkerMinDistance - fFloatQuestMarkerMaxDistance)) * 100.0;
if (v1 > 100.0)
return FLOAT_100_0;
result = 0.0;
if (v1 >= 0.0)
return v1;
return result;
}
#endif
static __declspec(noinline) bool DrawInWorldSpace(TESObjectREFR* apRefr, ImVec2& outViewPos)
{
// Attach at the head ish.
auto pos = apRefr->position;
pos.z += apRefr->GetHeight();
NiPoint3 screenPoint{};
HUDMenuUtils::WorldPtToScreenPt3(pos, screenPoint);
// Calculate window collision bounds.
auto* pViewport = BSGraphics::GetMainWindow();
// Translate to screen
const ImVec2 screenPos = ImVec2{
(pViewport->uiWindowWidth * screenPoint.x),
(pViewport->uiWindowHeight * (1.0f - screenPoint.y)),
};
const ImVec2 windowSize = {
static_cast<float>(pViewport->uiWindowWidth),
static_cast<float>(pViewport->uiWindowHeight),
};
auto IsVisible = [](const ImVec2& acVec2, const ImVec2& acScreenSize, float z) {
return (acVec2.x > 0 && acVec2.x <= acScreenSize.x) &&
(acVec2.y > 0 && acVec2.y <= acScreenSize.y) && z >= 0;
};
if (IsVisible(screenPos, windowSize, screenPoint.z))
{
outViewPos = screenPos;
return true;
}
outViewPos = {};
return false;
}
} // namespace
// TODO(Force): Net Histrogram (waves)
// Engine stuff.
// Fix cursor.
void DebugService::SetDebugId(const uint32_t aFormId) noexcept
{
m_formId = aFormId;
}
void DebugService::DrawComponentDebugView()
{
auto view = m_world.view<FormIdComponent>();
if (!m_formId)
return;
auto entityIt = std::find_if(view.begin(), view.end(), [id = m_formId, view](auto entity) { return view.get<FormIdComponent>(entity).Id == id; });
if (entityIt == view.end())
return;
auto entity = *entityIt;
if (auto* pObject = Cast<TESObjectREFR>(TESForm::GetById(m_formId)))
{
ImVec2 screenPos{};
if (DrawInWorldSpace(pObject, screenPos))
{
ImGui::SetNextWindowPos(screenPos);
ImGui::Begin("Component debug");
if (auto* pComponent = m_world.try_get<ReplayedActionsDebugComponent>(entity))
{
DisplayListOfReplayedActions(*pComponent, m_world.try_get<RemoteAnimationComponent>(entity));
}
if (auto serverIdRes = Utils::GetServerId(entity))
{
ImGui::InputScalar("Server ID", ImGuiDataType_U32, &(*serverIdRes), 0, 0, "%" PRIx32, ImGuiInputTextFlags_CharsHexadecimal);
}
if (auto* pComponent = m_world.try_get<LocalComponent>(entity))
{
if (ImGui::CollapsingHeader("LocalComponent"))
{
ImGui::InputScalar("Is dead?", ImGuiDataType_U8, &pComponent->IsDead, 0, 0, "%" PRIx8, ImGuiInputTextFlags_CharsHexadecimal);
}
}
if (auto* pComponent = m_world.try_get<LocalAnimationComponent>(entity))
{
if (ImGui::CollapsingHeader("LocalAnimationComponent"))
{
int actions = int(pComponent->Actions.size());
ImGui::InputInt("Number of actions", &actions, 0, 0, ImGuiInputTextFlags_ReadOnly);
}
}
if (auto* pComponent = m_world.try_get<RemoteComponent>(entity))
{
if (ImGui::CollapsingHeader("RemoteComponent"))
{
ImGui::InputScalar("Cached ref ID", ImGuiDataType_U32, &pComponent->CachedRefId, 0, 0, "%" PRIx32, ImGuiInputTextFlags_CharsHexadecimal);
}
}
if (auto* pComponent = m_world.try_get<InterpolationComponent>(entity))
{
if (ImGui::CollapsingHeader("InterpolationComponent"))
{
ImGui::Text("%f,%f,%f\n", pComponent->Position.x, pComponent->Position.y, pComponent->Position.z);
}
}
if (auto* pComponent = m_world.try_get<FaceGenComponent>(entity))
{
if (ImGui::CollapsingHeader("FaceGenComponent"))
{
for (auto x : pComponent->FaceTints.Entries)
{
ImGui::Text("Alpha %f, Color %u, Type %u\n", x.Alpha, x.Color, x.Type);
}
}
}
if (auto* pComponent = m_world.try_get<RemoteAnimationComponent>(entity))
{
if (ImGui::CollapsingHeader("RemoteAnimationComponent"))
{
ImGui::Text("EventName: %s\nTargetEventName: %s\nState1: %u\nState2: %u", pComponent->LastRanAction.EventName.c_str(), pComponent->LastRanAction.TargetEventName.c_str(), pComponent->LastRanAction.State1, pComponent->LastRanAction.State2);
}
}
ImGui::End();
}
}
}
void DebugService::DisplayListOfReplayedActions(const ReplayedActionsDebugComponent& aDebugComponent,
RemoteAnimationComponent* apAnimationComponent) const noexcept
{
const size_t total = aDebugComponent.ActionsReceivedForReplay.Actions.size();
const auto header = fmt::format("List of Replayed Actions ({})", total);
if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
String replayedActionsText;
if (aDebugComponent.ActionsReceivedForReplay.ResetAnimationGraph)
replayedActionsText += "<Animation graph reset>, ";
for (size_t i = 0; i < total; ++i)
{
if (i > 0)
replayedActionsText += ", ";
replayedActionsText += aDebugComponent.ActionsReceivedForReplay.Actions[i].EventName;
}
total == 0 ? replayedActionsText = "<None>" : replayedActionsText += '.';
ImGui::TextWrapped(replayedActionsText.c_str());
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Actions that were run (replayed) after this remote Actor received\n"
"spawn data from the server. Right click to replay again.");
}
if (ImGui::IsItemClicked(1) && apAnimationComponent && total > 0)
{
AnimationSystem::AddActionsForReplay(*apAnimationComponent, aDebugComponent.ActionsReceivedForReplay);
}
}
}