Rename plugin and add player position logging
Replace CommonLibF4 template identity with Fallout4Together across README, setup and xmake; update developer log with build/test entries. Implement player transform tracking in src: add PlayerTransform struct, change detection (position + wrapped Z rotation), throttling (minimum interval), and logging to Fallout4Together.log. Wire up F4SE messaging listener and a permanent task to poll on the game thread; include <chrono> and update startup log message. Add warnings for missing task/messaging interfaces and when player reference is unavailable.
This commit is contained in:
+151
-1
@@ -1,8 +1,158 @@
|
||||
namespace
|
||||
{
|
||||
struct PlayerTransform
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float angleZ;
|
||||
};
|
||||
|
||||
constexpr auto kPositionLogThreshold = 10.0F;
|
||||
constexpr auto kRotationLogThresholdDegrees = 1.0F;
|
||||
constexpr auto kRotationLogThresholdRadians = kRotationLogThresholdDegrees * 3.14159265358979323846F / 180.0F;
|
||||
constexpr auto kMinimumLogInterval = 1s;
|
||||
|
||||
RE::PlayerCharacter* TryGetLocalPlayer()
|
||||
{
|
||||
return RE::PlayerCharacter::GetSingleton();
|
||||
}
|
||||
|
||||
PlayerTransform GetPlayerTransform(const RE::PlayerCharacter& a_player)
|
||||
{
|
||||
const auto position = a_player.GetPosition();
|
||||
|
||||
return {
|
||||
position.x,
|
||||
position.y,
|
||||
position.z,
|
||||
a_player.data.angle.z
|
||||
};
|
||||
}
|
||||
|
||||
bool HasTransformChanged(const PlayerTransform& a_previous, const PlayerTransform& a_current)
|
||||
{
|
||||
const auto deltaX = a_current.x - a_previous.x;
|
||||
const auto deltaY = a_current.y - a_previous.y;
|
||||
const auto deltaZ = a_current.z - a_previous.z;
|
||||
auto deltaAngleZ = a_current.angleZ - a_previous.angleZ;
|
||||
|
||||
constexpr auto fullRotationRadians = 360.0F * 3.14159265358979323846F / 180.0F;
|
||||
constexpr auto halfRotationRadians = fullRotationRadians / 2.0F;
|
||||
while (deltaAngleZ > halfRotationRadians) {
|
||||
deltaAngleZ -= fullRotationRadians;
|
||||
}
|
||||
while (deltaAngleZ < -halfRotationRadians) {
|
||||
deltaAngleZ += fullRotationRadians;
|
||||
}
|
||||
|
||||
const auto squaredPositionDelta = (deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ);
|
||||
constexpr auto squaredPositionThreshold = kPositionLogThreshold * kPositionLogThreshold;
|
||||
|
||||
return squaredPositionDelta > squaredPositionThreshold ||
|
||||
deltaAngleZ > kRotationLogThresholdRadians || deltaAngleZ < -kRotationLogThresholdRadians;
|
||||
}
|
||||
|
||||
void LogPlayerTransform(const PlayerTransform& a_transform)
|
||||
{
|
||||
REX::INFO("Player position: X={:.2f}, Y={:.2f}, Z={:.2f}, AngleZ={:.2f}",
|
||||
a_transform.x,
|
||||
a_transform.y,
|
||||
a_transform.z,
|
||||
a_transform.angleZ);
|
||||
}
|
||||
|
||||
void CheckAndLogPlayerPositionChange()
|
||||
{
|
||||
const auto* player = TryGetLocalPlayer();
|
||||
if (!player) {
|
||||
static bool playerUnavailableWarningLogged = false;
|
||||
if (!playerUnavailableWarningLogged) {
|
||||
REX::WARN("Player position unavailable: local player reference is not available yet.");
|
||||
playerUnavailableWarningLogged = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static bool hasLastTransform = false;
|
||||
static PlayerTransform lastTransform{};
|
||||
static auto lastLogTime = std::chrono::steady_clock::now();
|
||||
|
||||
const auto currentTransform = GetPlayerTransform(*player);
|
||||
if (!hasLastTransform) {
|
||||
lastTransform = currentTransform;
|
||||
hasLastTransform = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasTransformChanged(lastTransform, currentTransform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto currentTime = std::chrono::steady_clock::now();
|
||||
if (currentTime - lastLogTime < kMinimumLogInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Player transforms can change by tiny amounts every frame. Throttling keeps the
|
||||
// readout useful for debugging movement without flooding Fallout4Together.log.
|
||||
LogPlayerTransform(currentTransform);
|
||||
lastTransform = currentTransform;
|
||||
lastLogTime = currentTime;
|
||||
}
|
||||
|
||||
void StartPlayerPositionPolling()
|
||||
{
|
||||
static bool pollingStarted = false;
|
||||
if (pollingStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* taskInterface = F4SE::GetTaskInterface();
|
||||
if (!taskInterface) {
|
||||
REX::WARN("Failed to get F4SE task interface; player position changes will not be logged.");
|
||||
return;
|
||||
}
|
||||
|
||||
// The player reference may not exist at plugin load time. A permanent task lets us
|
||||
// check on the game thread after load, while the logging gate keeps updates readable.
|
||||
taskInterface->AddTaskPermanent([]() {
|
||||
CheckAndLogPlayerPositionChange();
|
||||
});
|
||||
|
||||
pollingStarted = true;
|
||||
}
|
||||
|
||||
void F4SEAPI OnF4SEMessage(F4SE::MessagingInterface::Message* a_msg)
|
||||
{
|
||||
if (!a_msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a_msg->type) {
|
||||
case F4SE::MessagingInterface::kNewGame:
|
||||
case F4SE::MessagingInterface::kPostLoadGame:
|
||||
case F4SE::MessagingInterface::kGameLoaded:
|
||||
// Plugin load happens before a save/new game has finished creating the player.
|
||||
// These messages are the minimal safe timing point to start polling for movement.
|
||||
StartPlayerPositionPolling();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
F4SE_PLUGIN_LOAD(const F4SE::LoadInterface* a_f4se)
|
||||
{
|
||||
F4SE::Init(a_f4se);
|
||||
|
||||
REX::INFO("Hello World!");
|
||||
REX::INFO("Fallout 4 Together plugin loaded successfully.");
|
||||
|
||||
const auto* messaging = F4SE::GetMessagingInterface();
|
||||
if (!messaging || !messaging->RegisterListener(OnF4SEMessage)) {
|
||||
REX::WARN("Failed to register F4SE message listener; player position will not be logged.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <RE/Fallout.h>
|
||||
#include <F4SE/F4SE.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user