mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
fix(loot): DropClientLoot positions like live
Live DropClientLoot (12,501 decoded): use_position is set only when a player is the source (1,432, all activity rewards such as the dragon, Frakjaw and BONS chests); drops from enemies, smashables and chests leave it clear, so the client spawns the loot at the source object as it sees it and falls back to spawn_position only if that object is gone (LWODestroyableComponent::GetLootSpawnPos). Coins land where they spawn (final = spawn in all 3,158 coin drops); items land 10 units away (median 9.998, uniform direction) at spawn height. DLU always set use_position and scattered everything 4.2 units away. Inferred: the 10-unit rule for player-sourced items (live spread there ranges 0-58 units, source unknown). Check: kill enemies and smash crates: coins pop out of the object, items fly about 10 units away; open an activity chest (e.g. after a dragon or Frakjaw) and the loot still appears around you. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ set(DGAMETEST_SOURCES
|
||||
"SceneGhostingTests.cpp"
|
||||
"HolidayEventsTests.cpp"
|
||||
"SetCurrencySourceTests.cpp"
|
||||
"LootDropPositionTests.cpp"
|
||||
)
|
||||
|
||||
add_subdirectory(dComponentsTests)
|
||||
|
||||
74
tests/dGameTests/LootDropPositionTests.cpp
Normal file
74
tests/dGameTests/LootDropPositionTests.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "GameDependencies.h"
|
||||
#include "dGameMessagesTests/GameMessageTestUtils.h"
|
||||
|
||||
#include "InventoryMessages.h"
|
||||
#include "Loot.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace GameMessageTestUtils;
|
||||
|
||||
// DropClientLoot's use_position and final_position, as live sent them (12,501 live DropClientLoot).
|
||||
class LootDropPositionTests : public GameDependenciesTest {
|
||||
protected:
|
||||
void SetUp() override { SetUpDependencies(); }
|
||||
void TearDown() override { TearDownDependencies(); }
|
||||
};
|
||||
|
||||
// A live coin drop from an enemy with the player, loot and source IDs replaced: use_position false, final
|
||||
// position equal to the spawn position.
|
||||
TEST_F(LootDropPositionTests, CoinsLandWhereTheySpawn) {
|
||||
GameMessages::DropClientLoot lootMsg;
|
||||
lootMsg.target = 0x1000000000000001LL;
|
||||
lootMsg.ownerID = 0x1000000000000001LL;
|
||||
lootMsg.lootID = 0x0000000011223344LL;
|
||||
lootMsg.sourceID = 0x0102030405060708LL;
|
||||
lootMsg.currency = 1;
|
||||
lootMsg.item = LOT_NULL;
|
||||
lootMsg.spawnPos = NiPoint3(46.63258361816406f, 388.45635986328125f, -108.97083282470703f);
|
||||
Loot::SetDropPositions(lootMsg, false, 1.0f);
|
||||
|
||||
EXPECT_FALSE(lootMsg.bUsePosition);
|
||||
EXPECT_EQ(lootMsg.finalPosition, lootMsg.spawnPos);
|
||||
EXPECT_PACKET_EQ(FromHex(
|
||||
"53 05 00 0c 00 00 00 00 01 00 00 00 00 00 00 10 1e 00 71 21 ce 90 9a 8e b0 90 c4 7c 76 70 80 40 00 00 3f ff ff ff "
|
||||
"d1 0c c8 84 40 00 00 00 00 40 00 00 00 00 00 04 02 01 c1 81 41 00 c0 80 78 90 e7 48 4d 47 58 48 62 3e 3b 38 40", 595), StructPacket(lootMsg));
|
||||
}
|
||||
|
||||
TEST_F(LootDropPositionTests, ItemsLandTenUnitsAwayOnTheGround) {
|
||||
for (const float angle : { 0.0f, 1.0f, 3.14159265f, 5.5f }) {
|
||||
GameMessages::DropClientLoot lootMsg;
|
||||
lootMsg.item = 935;
|
||||
lootMsg.spawnPos = NiPoint3(100.0f, 20.0f, -50.0f);
|
||||
Loot::SetDropPositions(lootMsg, false, angle);
|
||||
|
||||
EXPECT_FALSE(lootMsg.bUsePosition);
|
||||
EXPECT_EQ(lootMsg.finalPosition.y, 20.0f);
|
||||
const auto dx = lootMsg.finalPosition.x - 100.0f;
|
||||
const auto dz = lootMsg.finalPosition.z + 50.0f;
|
||||
EXPECT_NEAR(std::sqrt(dx * dx + dz * dz), Loot::ITEM_DROP_DISTANCE, 1e-3f);
|
||||
EXPECT_NEAR(dx, std::sin(angle) * 10.0f, 1e-3f);
|
||||
EXPECT_NEAR(dz, std::cos(angle) * 10.0f, 1e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LootDropPositionTests, OnlyAPlayerSourceUsesThePosition) {
|
||||
GameMessages::DropClientLoot lootMsg;
|
||||
lootMsg.item = 935;
|
||||
lootMsg.spawnPos = NiPoint3(1.0f, 2.0f, 3.0f);
|
||||
Loot::SetDropPositions(lootMsg, true, 0.0f);
|
||||
EXPECT_TRUE(lootMsg.bUsePosition);
|
||||
|
||||
Loot::SetDropPositions(lootMsg, false, 0.0f);
|
||||
EXPECT_FALSE(lootMsg.bUsePosition);
|
||||
}
|
||||
|
||||
TEST_F(LootDropPositionTests, NoSpawnPositionLeavesTheMessageAlone) {
|
||||
GameMessages::DropClientLoot lootMsg;
|
||||
lootMsg.item = 935;
|
||||
Loot::SetDropPositions(lootMsg, true, 1.0f);
|
||||
EXPECT_FALSE(lootMsg.bUsePosition);
|
||||
EXPECT_EQ(lootMsg.finalPosition, NiPoint3Constant::ZERO);
|
||||
}
|
||||
Reference in New Issue
Block a user