mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Fix minimap arrow orientation and ground-detail foliage transparency
This commit is contained in:
parent
0631b9f5dc
commit
8efc1548dc
5 changed files with 45 additions and 91 deletions
|
|
@ -35,7 +35,8 @@ public:
|
|||
|
||||
/// Display quad — call INSIDE the main render pass.
|
||||
void render(VkCommandBuffer cmd, const Camera& playerCamera,
|
||||
const glm::vec3& centerWorldPos, int screenWidth, int screenHeight);
|
||||
const glm::vec3& centerWorldPos, int screenWidth, int screenHeight,
|
||||
float playerOrientation = 0.0f, bool hasPlayerOrientation = false);
|
||||
|
||||
void setEnabled(bool enabled) { this->enabled = enabled; }
|
||||
bool isEnabled() const { return enabled; }
|
||||
|
|
|
|||
|
|
@ -93,6 +93,13 @@ bool isClassicLikeExpansion() {
|
|||
return isActiveExpansion("classic") || isActiveExpansion("turtle");
|
||||
}
|
||||
|
||||
bool envFlagEnabled(const char* key, bool defaultValue = false) {
|
||||
const char* raw = std::getenv(key);
|
||||
if (!raw || !*raw) return defaultValue;
|
||||
return !(raw[0] == '0' || raw[0] == 'f' || raw[0] == 'F' ||
|
||||
raw[0] == 'n' || raw[0] == 'N');
|
||||
}
|
||||
|
||||
std::string formatCopperAmount(uint32_t amount) {
|
||||
uint32_t gold = amount / 10000;
|
||||
uint32_t silver = (amount / 100) % 100;
|
||||
|
|
@ -4621,6 +4628,7 @@ void GameHandler::setOrientation(float orientation) {
|
|||
}
|
||||
|
||||
void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
static const bool kVerboseUpdateObject = envFlagEnabled("WOWEE_LOG_UPDATE_OBJECT_VERBOSE", false);
|
||||
UpdateObjectData data;
|
||||
if (!packetParsers_->parseUpdateObject(packet, data)) {
|
||||
LOG_WARNING("Failed to parse SMSG_UPDATE_OBJECT");
|
||||
|
|
@ -5119,92 +5127,21 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
|
||||
// Extract XP / inventory slot / skill fields for player entity
|
||||
if (block.guid == playerGuid && block.objectType == ObjectType::PLAYER) {
|
||||
// Store baseline snapshot on first update
|
||||
static bool baselineStored = false;
|
||||
static std::map<uint16_t, uint32_t> baselineFields;
|
||||
|
||||
if (!baselineStored) {
|
||||
baselineFields = block.fields;
|
||||
baselineStored = true;
|
||||
LOG_INFO("===== BASELINE PLAYER FIELDS STORED =====");
|
||||
LOG_INFO(" Total fields: ", block.fields.size());
|
||||
}
|
||||
|
||||
// Diff against baseline to find changes
|
||||
std::vector<uint16_t> changedIndices;
|
||||
std::vector<uint16_t> newIndices;
|
||||
std::vector<uint16_t> removedIndices;
|
||||
|
||||
for (const auto& [idx, val] : block.fields) {
|
||||
auto it = baselineFields.find(idx);
|
||||
if (it == baselineFields.end()) {
|
||||
newIndices.push_back(idx);
|
||||
} else if (it->second != val) {
|
||||
changedIndices.push_back(idx);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [idx, val] : baselineFields) {
|
||||
if (block.fields.find(idx) == block.fields.end()) {
|
||||
removedIndices.push_back(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-detect coinage index using the previous snapshot vs this full snapshot.
|
||||
maybeDetectCoinageIndex(lastPlayerFields_, block.fields);
|
||||
|
||||
lastPlayerFields_ = block.fields;
|
||||
detectInventorySlotBases(block.fields);
|
||||
|
||||
// Debug: Show field changes
|
||||
LOG_INFO("Player update with ", block.fields.size(), " fields");
|
||||
|
||||
if (!changedIndices.empty() || !newIndices.empty() || !removedIndices.empty()) {
|
||||
LOG_INFO(" ===== FIELD CHANGES DETECTED =====");
|
||||
if (!changedIndices.empty()) {
|
||||
LOG_INFO(" Changed fields (", changedIndices.size(), "):");
|
||||
std::sort(changedIndices.begin(), changedIndices.end());
|
||||
for (size_t i = 0; i < std::min(size_t(30), changedIndices.size()); ++i) {
|
||||
uint16_t idx = changedIndices[i];
|
||||
uint32_t oldVal = baselineFields[idx];
|
||||
uint32_t newVal = block.fields.at(idx);
|
||||
LOG_INFO(" [", idx, "]: ", oldVal, " -> ", newVal,
|
||||
" (0x", std::hex, oldVal, " -> 0x", newVal, std::dec, ")");
|
||||
}
|
||||
if (changedIndices.size() > 30) {
|
||||
LOG_INFO(" ... (", changedIndices.size() - 30, " more)");
|
||||
}
|
||||
}
|
||||
if (!newIndices.empty()) {
|
||||
LOG_INFO(" New fields (", newIndices.size(), "):");
|
||||
std::sort(newIndices.begin(), newIndices.end());
|
||||
for (size_t i = 0; i < std::min(size_t(20), newIndices.size()); ++i) {
|
||||
uint16_t idx = newIndices[i];
|
||||
uint32_t val = block.fields.at(idx);
|
||||
LOG_INFO(" [", idx, "]: ", val, " (0x", std::hex, val, std::dec, ")");
|
||||
}
|
||||
if (newIndices.size() > 20) {
|
||||
LOG_INFO(" ... (", newIndices.size() - 20, " more)");
|
||||
}
|
||||
}
|
||||
if (!removedIndices.empty()) {
|
||||
LOG_INFO(" Removed fields (", removedIndices.size(), "):");
|
||||
std::sort(removedIndices.begin(), removedIndices.end());
|
||||
for (size_t i = 0; i < std::min(size_t(20), removedIndices.size()); ++i) {
|
||||
uint16_t idx = removedIndices[i];
|
||||
uint32_t val = baselineFields.at(idx);
|
||||
LOG_INFO(" [", idx, "]: was ", val, " (0x", std::hex, val, std::dec, ")");
|
||||
}
|
||||
if (kVerboseUpdateObject) {
|
||||
uint16_t maxField = 0;
|
||||
for (const auto& [key, _val] : block.fields) {
|
||||
if (key > maxField) maxField = key;
|
||||
}
|
||||
LOG_INFO("Player update with ", block.fields.size(),
|
||||
" fields (max index=", maxField, ")");
|
||||
}
|
||||
|
||||
uint16_t maxField = 0;
|
||||
for (const auto& [key, val] : block.fields) {
|
||||
if (key > maxField) maxField = key;
|
||||
}
|
||||
|
||||
LOG_INFO(" Highest field index: ", maxField);
|
||||
|
||||
bool slotsChanged = false;
|
||||
const uint16_t ufPlayerXp = fieldIndex(UF::PLAYER_XP);
|
||||
const uint16_t ufPlayerNextXp = fieldIndex(UF::PLAYER_NEXT_LEVEL_XP);
|
||||
|
|
@ -5222,11 +5159,11 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
}
|
||||
else if (key == ufCoinage) {
|
||||
playerMoneyCopper_ = val;
|
||||
LOG_INFO("Money set from update fields: ", val, " copper");
|
||||
LOG_DEBUG("Money set from update fields: ", val, " copper");
|
||||
}
|
||||
else if (ufArmor != 0xFFFF && key == ufArmor) {
|
||||
playerArmorRating_ = static_cast<int32_t>(val);
|
||||
LOG_INFO("Armor rating from update fields: ", playerArmorRating_);
|
||||
LOG_DEBUG("Armor rating from update fields: ", playerArmorRating_);
|
||||
}
|
||||
// Do not synthesize quest-log entries from raw update-field slots.
|
||||
// Slot layouts differ on some classic-family realms and can produce
|
||||
|
|
@ -5502,15 +5439,15 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
for (const auto& [key, val] : block.fields) {
|
||||
if (key == ufPlayerXp) {
|
||||
playerXp_ = val;
|
||||
LOG_INFO("XP updated: ", val);
|
||||
LOG_DEBUG("XP updated: ", val);
|
||||
}
|
||||
else if (key == ufPlayerNextXp) {
|
||||
playerNextLevelXp_ = val;
|
||||
LOG_INFO("Next level XP updated: ", val);
|
||||
LOG_DEBUG("Next level XP updated: ", val);
|
||||
}
|
||||
else if (key == ufPlayerLevel) {
|
||||
serverPlayerLevel_ = val;
|
||||
LOG_INFO("Level updated: ", val);
|
||||
LOG_DEBUG("Level updated: ", val);
|
||||
for (auto& ch : characters) {
|
||||
if (ch.guid == playerGuid) {
|
||||
ch.level = val;
|
||||
|
|
@ -5520,7 +5457,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
}
|
||||
else if (key == ufCoinage) {
|
||||
playerMoneyCopper_ = val;
|
||||
LOG_INFO("Money updated via VALUES: ", val, " copper");
|
||||
LOG_DEBUG("Money updated via VALUES: ", val, " copper");
|
||||
}
|
||||
else if (ufArmor != 0xFFFF && key == ufArmor) {
|
||||
playerArmorRating_ = static_cast<int32_t>(val);
|
||||
|
|
|
|||
|
|
@ -2301,7 +2301,8 @@ void M2Renderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const
|
|||
effectiveBlendMode = 3;
|
||||
}
|
||||
if (model.isGroundDetail) {
|
||||
effectiveBlendMode = 2;
|
||||
// Treat foliage cards as cutout so they depth-sort correctly.
|
||||
effectiveBlendMode = 1;
|
||||
}
|
||||
|
||||
VkPipeline desiredPipeline;
|
||||
|
|
@ -2329,9 +2330,9 @@ void M2Renderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const
|
|||
if (batch.colorKeyBlack) {
|
||||
mat->colorKeyThreshold = (effectiveBlendMode == 4 || effectiveBlendMode == 5) ? 0.7f : 0.08f;
|
||||
}
|
||||
// Ground detail: override alphaTest and unlit
|
||||
// Ground detail: force cutout shading for stable two-sided foliage.
|
||||
if (model.isGroundDetail) {
|
||||
mat->alphaTest = 0;
|
||||
mat->alphaTest = 1;
|
||||
mat->unlit = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -472,7 +472,8 @@ void Minimap::compositePass(VkCommandBuffer cmd, const glm::vec3& centerWorldPos
|
|||
|
||||
void Minimap::render(VkCommandBuffer cmd, const Camera& playerCamera,
|
||||
const glm::vec3& centerWorldPos,
|
||||
int screenWidth, int screenHeight) {
|
||||
int screenWidth, int screenHeight,
|
||||
float playerOrientation, bool hasPlayerOrientation) {
|
||||
if (!enabled || !hasCachedFrame || !displayPipeline) return;
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, displayPipeline);
|
||||
|
|
@ -511,8 +512,15 @@ void Minimap::render(VkCommandBuffer cmd, const Camera& playerCamera,
|
|||
|
||||
float arrowRotation = 0.0f;
|
||||
if (!rotateWithCamera) {
|
||||
glm::vec3 fwd = playerCamera.getForward();
|
||||
arrowRotation = std::atan2(-fwd.x, fwd.y);
|
||||
// Prefer authoritative player orientation for north-up minimap arrow.
|
||||
// Canonical yaw already matches minimap rotation convention:
|
||||
// 0=north, +pi/2=east.
|
||||
if (hasPlayerOrientation) {
|
||||
arrowRotation = playerOrientation;
|
||||
} else {
|
||||
glm::vec3 fwd = playerCamera.getForward();
|
||||
arrowRotation = std::atan2(-fwd.x, fwd.y);
|
||||
}
|
||||
}
|
||||
|
||||
MinimapDisplayPush push{};
|
||||
|
|
|
|||
|
|
@ -3183,8 +3183,15 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) {
|
|||
glm::vec3 minimapCenter = camera->getPosition();
|
||||
if (cameraController && cameraController->isThirdPerson())
|
||||
minimapCenter = characterPosition;
|
||||
float minimapPlayerOrientation = 0.0f;
|
||||
bool hasMinimapPlayerOrientation = false;
|
||||
if (gameHandler) {
|
||||
minimapPlayerOrientation = gameHandler->getMovementInfo().orientation;
|
||||
hasMinimapPlayerOrientation = true;
|
||||
}
|
||||
minimap->render(currentCmd, *camera, minimapCenter,
|
||||
window->getWidth(), window->getHeight());
|
||||
window->getWidth(), window->getHeight(),
|
||||
minimapPlayerOrientation, hasMinimapPlayerOrientation);
|
||||
}
|
||||
|
||||
auto renderEnd = std::chrono::steady_clock::now();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue