diff --git a/src/client/ClientServices.cpp b/src/client/ClientServices.cpp index d95af16..7ce248e 100644 --- a/src/client/ClientServices.cpp +++ b/src/client/ClientServices.cpp @@ -71,7 +71,7 @@ void ClientServices::GetRealmList() { } void ClientServices::GetCharacterList() { - // TODO + ClientServices::s_currentConnection->GetCharacterList(); } REALM_INFO* ClientServices::GetRealmInfoByIndex(int32_t index) { diff --git a/src/glue/CCharacterSelection.cpp b/src/glue/CCharacterSelection.cpp index e189f32..7081264 100644 --- a/src/glue/CCharacterSelection.cpp +++ b/src/glue/CCharacterSelection.cpp @@ -4,6 +4,7 @@ TSGrowableArray CCharacterSelection::s_characterList; CSimpleModelFFX* CCharacterSelection::s_modelFrame; +float CCharacterSelection::s_charFacing = 0.0f; void CCharacterSelection::RenderPrep() { // TODO @@ -33,3 +34,7 @@ void CCharacterSelection::SetBackgroundModel(const char* modelPath) { model->IsDrawable(1, 1); } } + +void CCharacterSelection::SetCharFacing(float facing) { + // TODO: +} diff --git a/src/glue/CCharacterSelection.hpp b/src/glue/CCharacterSelection.hpp index 29dbdc7..6d3d9ab 100644 --- a/src/glue/CCharacterSelection.hpp +++ b/src/glue/CCharacterSelection.hpp @@ -14,10 +14,12 @@ class CCharacterSelection { // Static variables static TSGrowableArray s_characterList; static CSimpleModelFFX* s_modelFrame; + static float s_charFacing; // Static functions static void RenderPrep(); static void SetBackgroundModel(const char* modelPath); + static void SetCharFacing(float facing); }; #endif diff --git a/src/net/Types.hpp b/src/net/Types.hpp index b70de69..fa3d356 100644 --- a/src/net/Types.hpp +++ b/src/net/Types.hpp @@ -1,6 +1,8 @@ #ifndef NET_TYPES_HPP #define NET_TYPES_HPP +#include + #include enum LOGIN_RESULT { @@ -1252,4 +1254,36 @@ struct REALM_INFO { uint16_t revision; }; +struct INVENTORY_ITEM { + uint8_t type; + uint32_t displayID; + uint32_t auraID; +}; + +struct CHARACTER_INFO { + uint64_t guid; + char name[48]; + uint32_t mapID; + uint32_t zoneID; + uint32_t guildID; + C3Vector position; + INVENTORY_ITEM items[23]; + uint32_t petDisplayInfoID; + uint32_t petExperienceLevel; + uint32_t petCreatureFamilyID; + uint32_t flags; + uint32_t customizeFlags; + uint8_t raceID; + uint8_t classID; + uint8_t sexID; + uint8_t skinID; + uint8_t faceID; + uint8_t hairStyleID; + uint8_t hairColorID; + uint8_t facialHairStyleID; + uint8_t experienceLevel; + uint8_t firstLogin; +}; + + #endif diff --git a/src/net/connection/ClientConnection.cpp b/src/net/connection/ClientConnection.cpp index 3e70e09..64ca443 100644 --- a/src/net/connection/ClientConnection.cpp +++ b/src/net/connection/ClientConnection.cpp @@ -132,6 +132,15 @@ void ClientConnection::AccountLogin_Queued() { // TODO CGlueMgr::UpdateWaitQueue(this->m_queuePosition); } +void ClientConnection::GetCharacterList() { + this->Initiate(COP_GET_CHARACTERS, 43, nullptr); + if (this->m_connected) { + this->RequestCharacterEnum(); + } else { + this->Cancel(4); + } +} + void ClientConnection::Cancel(int32_t errorCode) { this->Complete(0, errorCode); } diff --git a/src/net/connection/ClientConnection.hpp b/src/net/connection/ClientConnection.hpp index 8504c4d..9e7e866 100644 --- a/src/net/connection/ClientConnection.hpp +++ b/src/net/connection/ClientConnection.hpp @@ -18,6 +18,7 @@ class ClientConnection : public RealmConnection { // Virtual member functions virtual int32_t HandleConnect(); + virtual void Complete(int32_t result, int32_t errorCode); // Member functions ClientConnection(RealmResponse* realmResponse) @@ -26,9 +27,9 @@ class ClientConnection : public RealmConnection { void AccountLogin(const char* name, const char* password, int32_t region, int32_t locale); void AccountLogin_Finish(int32_t authResult); void AccountLogin_Queued(); + void GetCharacterList(); void Cancel(int32_t errorCode); void Cleanup(); - void Complete(int32_t result, int32_t errorCode); void Connect(); int32_t Disconnect(); void Initiate(WOWCS_OPS op, int32_t errorCode, void (*cleanup)()); diff --git a/src/net/connection/RealmConnection.cpp b/src/net/connection/RealmConnection.cpp index 0ba58f6..5c7a958 100644 --- a/src/net/connection/RealmConnection.cpp +++ b/src/net/connection/RealmConnection.cpp @@ -24,7 +24,7 @@ int32_t RealmConnection::MessageHandler(void* param, NETMESSAGE msgId, uint32_t } case SMSG_ENUM_CHARACTERS_RESULT: { - // TODO + result = connection->HandleCharEnum(msgId, time, msg); break; } @@ -192,6 +192,98 @@ int32_t RealmConnection::HandleAuthResponse(uint32_t msgId, uint32_t time, CData return 1; } +int32_t RealmConnection::HandleCharEnum(uint32_t msgId, uint32_t time, CDataStore* msg) { + if (this->m_realmResponse) { + this->m_realmResponse->GameServerResult(this, "SMSG_CHAR_ENUM", nullptr, nullptr); + } + + uint8_t count; + msg->Get(count); + + bool overflow = false; + if (count > 10) { + count = 0; + overflow = true; + } + + m_characterList.SetCount(count); + + for (uint32_t i = 0; i < count; ++i) { + auto& character = m_characterList[i]; + msg->Get(character.guid); + msg->GetString(character.name, 48); + msg->Get(character.raceID); + msg->Get(character.classID); + msg->Get(character.sexID); + msg->Get(character.skinID); + msg->Get(character.faceID); + msg->Get(character.hairStyleID); + msg->Get(character.hairColorID); + msg->Get(character.facialHairStyleID); + msg->Get(character.experienceLevel); + msg->Get(character.zoneID); + msg->Get(character.mapID); + msg->Get(character.position.x); + msg->Get(character.position.y); + msg->Get(character.position.z); + msg->Get(character.guildID); + msg->Get(character.flags); + msg->Get(character.customizeFlags); + msg->Get(character.firstLogin); + msg->Get(character.petDisplayInfoID); + msg->Get(character.petExperienceLevel); + msg->Get(character.petCreatureFamilyID); + for (uint32_t j = 0; j < 23; ++j) { + msg->Get(character.items[j].displayID); + msg->Get(character.items[j].type); + msg->Get(character.items[j].auraID); + } + } + + bool success = false; + if (msg->IsRead()) { + if (!overflow) { + success = true; + } + } else if (!overflow) { + // TODO: Proper implementation + uint32_t value; + msg->Get(value); + msg->Get(value); + msg->Get(value); + msg->Get(value); + msg->Get(value); + msg->Get(value); + msg->Get(value); + msg->Get(value); + msg->Get(value); + msg->Get(value); + if (msg->IsRead()) { + success = true; + } + } + + if (!success) { + m_characterList.Clear(); + } + + // TODO: Should be implemented as call of sub_6B2000 + if (success) { + this->Complete(1, 44); + } else { + this->Complete(1, 45); + } + + return 1; +} + void RealmConnection::SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4) { // TODO } + +void RealmConnection::RequestCharacterEnum() { + CDataStore msg; + msg.Put(static_cast(CMSG_ENUM_CHARACTERS)); + msg.Finalize(); + this->Send(&msg); +} diff --git a/src/net/connection/RealmConnection.hpp b/src/net/connection/RealmConnection.hpp index 5414dc2..28a8531 100644 --- a/src/net/connection/RealmConnection.hpp +++ b/src/net/connection/RealmConnection.hpp @@ -24,6 +24,7 @@ class RealmConnection : public NetClient { // Member variables RealmResponse* m_realmResponse; + TSFixedArray m_characterList; uint8_t m_authenticated = 0; uint32_t m_queuePosition = 0; uint32_t m_freeCharacterMigration = 0; @@ -34,11 +35,14 @@ class RealmConnection : public NetClient { // Virtual member functions virtual int32_t HandleAuthChallenge(AuthenticationChallenge* challenge); + virtual void Complete(int32_t result, int32_t errorCode) = 0; // Member functions RealmConnection(RealmResponse* realmResponse); int32_t HandleAuthResponse(uint32_t msgId, uint32_t time, CDataStore* msg); + int32_t HandleCharEnum(uint32_t msgId, uint32_t time, CDataStore* msg); void SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4); + void RequestCharacterEnum(); }; #endif diff --git a/src/ui/ScriptFunctionsCharSelect.cpp b/src/ui/ScriptFunctionsCharSelect.cpp index b67314a..7979442 100644 --- a/src/ui/ScriptFunctionsCharSelect.cpp +++ b/src/ui/ScriptFunctionsCharSelect.cpp @@ -74,11 +74,19 @@ int32_t Script_UpdateSelectionCustomizationScene(lua_State* L) { } int32_t Script_GetCharacterSelectFacing(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + // Radian to Degree + lua_pushnumber(L, CCharacterSelection::s_charFacing * 57.29578f); + return 1; } int32_t Script_SetCharacterSelectFacing(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isnumber(L, 1)) { + luaL_error(L, "Usage: SetCharacterSelectFacing(degrees)"); + } + // Degree to Radian + float facing = lua_tonumber(L, 1) * 0.017453292; + CCharacterSelection::SetCharFacing(facing); + return 1; } int32_t Script_GetSelectBackgroundModel(lua_State* L) { diff --git a/src/ui/ScriptFunctionsGlueScriptEvents.cpp b/src/ui/ScriptFunctionsGlueScriptEvents.cpp index d8e4903..8b7fcf7 100644 --- a/src/ui/ScriptFunctionsGlueScriptEvents.cpp +++ b/src/ui/ScriptFunctionsGlueScriptEvents.cpp @@ -5,6 +5,7 @@ #include "glue/CGlueMgr.hpp" #include "gx/Coordinate.hpp" #include "net/connection/ClientConnection.hpp" +#include "net/Login.hpp" #include "ui/CSimpleTop.hpp" #include "ui/Types.hpp" #include "console/CVar.hpp" @@ -19,11 +20,11 @@ int32_t Script_IsShiftKeyDown(lua_State* L) { } int32_t Script_GetBuildInfo(lua_State* L) { - auto version = FrameScript_GetText("VERSION", -1, GENDER_NOT_APPLICABLE); - lua_pushstring(L, version); + auto szVersion = FrameScript_GetText("VERSION", -1, GENDER_NOT_APPLICABLE); + auto szVersionType = FrameScript_GetText("RELEASE_BUILD", -1, GENDER_NOT_APPLICABLE); - auto releaseBuild = FrameScript_GetText("RELEASE_BUILD", -1, GENDER_NOT_APPLICABLE); - lua_pushstring(L, releaseBuild); + lua_pushstring(L, szVersion); + lua_pushstring(L, szVersionType); lua_pushstring(L, "3.3.5"); lua_pushstring(L, "12340"); lua_pushstring(L, "Jun 24 2010"); @@ -274,7 +275,12 @@ int32_t Script_GetServerName(lua_State* L) { } int32_t Script_DisconnectFromServer(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (ClientServices::Connection()->IsConnected()) { + CGlueMgr::m_disconnectPending = 1; + ClientServices::Connection()->Disconnect(); + } + ClientServices::LoginConnection()->Logoff(); + return 0; } int32_t Script_IsConnectedToServer(lua_State* L) {