diff --git a/Source/Client/Mode/CGameMode.h b/Source/Client/Mode/CGameMode.h index 38a0fe92..4e1a806a 100644 --- a/Source/Client/Mode/CGameMode.h +++ b/Source/Client/Mode/CGameMode.h @@ -271,6 +271,7 @@ public: std::string ActorName(std::uint32_t id); std::uint32_t ActorNameColor(int job, std::uint32_t aid); const CActorNameCard& LookupNameCard(std::uint32_t id); + std::vector BuildActorEntryPacket(CGameActor* actor, std::uint16_t packetType); const char* DragItemName(); void PushUnknown01A4(int value); bool IsOverWeight(bool notify); diff --git a/Source/EntityInit.cpp b/Source/EntityInit.cpp new file mode 100644 index 00000000..83f2043e --- /dev/null +++ b/Source/EntityInit.cpp @@ -0,0 +1,238 @@ +#include "Client/Mode/CGameMode.h" +#include "Contents/Actors/GameActor.h" +#include "Contents/Actors/Pc.h" +#include "Contents/GuildMgr.h" + +#include +#include +#include +#include +#include + +namespace { +#pragma pack(push, 1) + struct ActorMoveEntryPacket { + /* 0000 */ std::uint16_t packetType; + /* 0002 */ std::uint16_t packetLength; + /* 0004 */ std::uint8_t objectType; + /* 0005 */ std::uint32_t accountId; + /* 0009 */ std::uint32_t characterId; + /* 000D */ std::uint16_t speed; + /* 000F */ std::uint16_t bodyState; + /* 0011 */ std::uint16_t healthState; + /* 0013 */ std::uint32_t effectState; + /* 0017 */ std::uint16_t job; + /* 0019 */ std::uint16_t head; + /* 001B */ std::int64_t weapon; + /* 0023 */ std::uint16_t accessory; + /* 0025 */ std::uint32_t moveStartTime; + /* 0029 */ std::uint16_t accessory2; + /* 002B */ std::uint16_t accessory3; + /* 002D */ std::uint16_t headPalette; + /* 002F */ std::uint16_t bodyPalette; + /* 0031 */ std::uint16_t headDirection; + /* 0033 */ std::uint16_t robe; + /* 0035 */ std::uint32_t guildId; + /* 0039 */ std::uint16_t emblemVersion; + /* 003B */ std::uint16_t honor; + /* 003D */ std::uint32_t virtue; + /* 0041 */ std::uint8_t isPkModeOn; + /* 0042 */ std::uint8_t sex; + /* 0043 */ std::uint8_t moveData[6]; + /* 0049 */ std::uint8_t xSize; + /* 004A */ std::uint8_t ySize; + /* 004B */ std::uint16_t level; + /* 004D */ std::uint16_t font; + /* 004F */ std::int32_t maxHp; + /* 0053 */ std::int32_t hp; + /* 0057 */ std::uint8_t isBoss; + /* 0058 */ std::uint16_t body; + }; + + struct ActorStandEntryPacket { + /* 0000 */ std::uint16_t packetType; + /* 0002 */ std::uint16_t packetLength; + /* 0004 */ std::uint8_t objectType; + /* 0005 */ std::uint32_t accountId; + /* 0009 */ std::uint32_t characterId; + /* 000D */ std::uint16_t speed; + /* 000F */ std::uint16_t bodyState; + /* 0011 */ std::uint16_t healthState; + /* 0013 */ std::uint32_t effectState; + /* 0017 */ std::uint16_t job; + /* 0019 */ std::uint16_t head; + /* 001B */ std::int64_t weapon; + /* 0023 */ std::uint16_t accessory; + /* 0025 */ std::uint16_t accessory2; + /* 0027 */ std::uint16_t accessory3; + /* 0029 */ std::uint16_t headPalette; + /* 002B */ std::uint16_t bodyPalette; + /* 002D */ std::uint16_t headDirection; + /* 002F */ std::uint16_t robe; + /* 0031 */ std::uint32_t guildId; + /* 0035 */ std::uint16_t emblemVersion; + /* 0037 */ std::uint16_t honor; + /* 0039 */ std::uint32_t virtue; + /* 003D */ std::uint8_t isPkModeOn; + /* 003E */ std::uint8_t sex; + /* 003F */ std::uint8_t posDir[3]; + /* 0042 */ std::uint8_t xSize; + /* 0043 */ std::uint8_t ySize; + /* 0044 */ std::uint8_t state; + /* 0045 */ std::uint16_t level; + /* 0047 */ std::uint16_t font; + /* 0049 */ std::int32_t maxHp; + /* 004D */ std::int32_t hp; + /* 0051 */ std::uint8_t isBoss; + /* 0052 */ std::uint16_t body; + }; +#pragma pack(pop) + + static_assert(sizeof(ActorMoveEntryPacket) == 0x5A); + static_assert(sizeof(ActorStandEntryPacket) == 0x54); +} + +// OFFSET: 0x00CD47F0 +// FUNCTION: fn_21275 +std::vector CGameMode::BuildActorEntryPacket(CGameActor* actor, std::uint16_t packetType) { + std::vector packet; + std::string name = this->nameCard.Name(actor->render.accountId); + + if (actor->render.unknown_0070 == 1) { + packet.resize(sizeof(ActorMoveEntryPacket)); + ActorMoveEntryPacket* entry = reinterpret_cast(packet.data()); + entry->hp = actor->GetGaugeCurrent(); + entry->maxHp = actor->GetGaugeMaximum(); + entry->isBoss = actor->unknown_0304; + entry->moveStartTime = actor->routeStartTick; + + int metadata = 0; + float x = 0.0f; + float y = 0.0f; + actor->route.Sample(timeGetTime(), &x, &y, &metadata); + + int cellX; + int subX; + if (x > 0.0f) { + const double position = x + 0.5; + cellX = static_cast(position); + subX = static_cast(static_cast(position - cellX) * 16.0f); + } else { + cellX = 0; + subX = 0; + } + + int cellY; + int subY; + if (y > 0.0f) { + const double position = y + 0.5; + cellY = static_cast(position); + subY = static_cast(static_cast(position - cellY) * 16.0f); + } else { + cellY = 0; + subY = 0; + } + + const int destinationX = actor->unknown_0158[5]; + const int destinationY = *reinterpret_cast(actor->unknown_0170); + entry->moveData[0] = static_cast(cellX >> 2); + entry->moveData[1] = static_cast((cellX << 6) | ((cellY >> 4) & 0x3F)); + entry->moveData[2] = static_cast((cellY << 4) | ((destinationX >> 6) & 0x0F)); + entry->moveData[3] = static_cast((destinationX << 2) | ((destinationY >> 8) & 0x03)); + entry->moveData[4] = static_cast(destinationY); + entry->moveData[5] = static_cast((subX << 4) | (subY & 0x0F)); + + entry->packetType = packetType; + entry->packetLength = static_cast(name.size() + packet.size()); + entry->objectType = actor->unknown_0314; + entry->accountId = actor->render.accountId; + entry->speed = *reinterpret_cast(actor->unknown_0170 + 4); + entry->bodyState = static_cast(actor->bodyState); + entry->healthState = static_cast(actor->unknown_02C4); + entry->effectState = actor->Slot13(); + entry->job = static_cast(actor->GetEffectiveJob(-1)); + entry->head = *reinterpret_cast(actor->unknown_029C); + entry->guildId = actor->Slot50(); + entry->emblemVersion = static_cast(g_guildMgr->GetEmblemVersion(actor->Slot50())); + entry->isPkModeOn = actor->unknown_02C8 != 0; + entry->sex = static_cast(actor->unknown_0260); + entry->xSize = static_cast(actor->unknown_0294); + entry->ySize = static_cast(actor->unknown_0298); + entry->level = actor->unknown_0210; + entry->font = static_cast(actor->render.unknown_00FC); + entry->bodyPalette = static_cast(actor->render.unknown_0048); + + if (actor->unknown_0314 == 0) { + CPc* pc = static_cast(actor); + entry->honor = static_cast(pc->unknown_0430); + entry->virtue = pc->unknown_0434; + entry->headDirection = static_cast(pc->unknown_043C); + entry->weapon = pc->unknown_0434; + entry->accessory = static_cast(pc->unknown_0450); + entry->accessory2 = static_cast(pc->unknown_0454); + entry->accessory3 = static_cast(pc->unknown_0458); + entry->headPalette = static_cast(pc->unknown_0444); + entry->robe = static_cast(pc->unknown_049C); + entry->characterId = pc->Slot42(); + entry->body = static_cast(pc->Slot46()); + } + } else { + packet.resize(sizeof(ActorStandEntryPacket)); + ActorStandEntryPacket* entry = reinterpret_cast(packet.data()); + entry->hp = actor->GetGaugeCurrent(); + entry->maxHp = actor->GetGaugeMaximum(); + entry->isBoss = actor->unknown_0304; + + const int direction = (static_cast(actor->render.angle) + 180) / 45 % 8; + const int cellX = actor->unknown_0158[5]; + const int cellY = *reinterpret_cast(actor->unknown_0170); + entry->posDir[0] = static_cast(cellX >> 2); + entry->posDir[1] = static_cast((cellX << 6) | ((cellY >> 4) & 0x3F)); + entry->posDir[2] = static_cast((cellY << 4) | (direction & 0x0F)); + + if (actor->render.unknown_0070 == 3) { + entry->state = 1; + } else { + entry->state = actor->render.unknown_0070 == 6 ? 2 : 0; + } + + entry->packetType = packetType; + entry->packetLength = static_cast(name.size() + packet.size()); + entry->objectType = actor->unknown_0314; + entry->accountId = actor->render.accountId; + entry->speed = *reinterpret_cast(actor->unknown_0170 + 4); + entry->bodyState = static_cast(actor->bodyState); + entry->healthState = static_cast(actor->unknown_02C4); + entry->effectState = actor->Slot13(); + entry->job = static_cast(actor->GetEffectiveJob(-1)); + entry->head = *reinterpret_cast(actor->unknown_029C); + entry->guildId = actor->Slot50(); + entry->emblemVersion = static_cast(g_guildMgr->GetEmblemVersion(actor->Slot50())); + entry->isPkModeOn = actor->unknown_02C8 != 0; + entry->sex = static_cast(actor->unknown_0260); + entry->xSize = static_cast(actor->unknown_0294); + entry->ySize = static_cast(actor->unknown_0298); + entry->level = actor->unknown_0210; + entry->font = static_cast(actor->render.unknown_00FC); + entry->bodyPalette = static_cast(actor->render.unknown_0048); + entry->emblemVersion = static_cast(g_guildMgr->GetEmblemVersion(actor->Slot50())); + + if (actor->unknown_0314 == 0) { + CPc* pc = static_cast(actor); + entry->honor = static_cast(pc->unknown_0430); + entry->virtue = pc->unknown_0434; + entry->headDirection = static_cast(pc->unknown_043C); + entry->weapon = pc->unknown_0434; + entry->accessory = static_cast(pc->unknown_0450); + entry->accessory2 = static_cast(pc->unknown_0454); + entry->accessory3 = static_cast(pc->unknown_0458); + entry->headPalette = static_cast(pc->unknown_0444); + entry->robe = static_cast(pc->unknown_049C); + entry->characterId = pc->Slot42(); + entry->body = static_cast(pc->Slot46()); + } + } + + packet.insert(packet.end(), name.begin(), name.end()); + return packet; +} diff --git a/data/compile.json b/data/compile.json index 4c391d1a..ab4e880a 100644 --- a/data/compile.json +++ b/data/compile.json @@ -666,6 +666,7 @@ "Source/Contents/World/WorldViewSpatial.cpp": 3, "Source/Contents/WorldNavigation.cpp": 4, "Source/Contents/WorldView/WorldViewData.cpp": 4, + "Source/EntityInit.cpp": 4, "Source/File/CommonObject.cpp": 1, "Source/File/DirectoryRemoval.cpp": 1, "Source/File/File.cpp": 1,