From f2a253f5ad876c88de5ac1fbf4cd8636379a147a Mon Sep 17 00:00:00 2001 From: VDm Date: Sat, 17 May 2025 20:00:10 +0400 Subject: [PATCH] feat: update CCharacterComponent and CCharacterCreation classes --- src/client/Client.cpp | 3 +- src/glue/CCharacterComponent.cpp | 135 +++++++++++++++++++++++++++ src/glue/CCharacterComponent.hpp | 45 +++++++++ src/glue/CCharacterCreation.cpp | 110 +++++++++++++++++++++- src/glue/CCharacterCreation.hpp | 25 ++++- src/glue/CGlueMgr.cpp | 11 +-- src/net/Types.hpp | 7 +- src/ui/ScriptFunctionsCharCreate.cpp | 34 +++++-- 8 files changed, 348 insertions(+), 22 deletions(-) diff --git a/src/client/Client.cpp b/src/client/Client.cpp index b2390a0..095cd14 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -12,6 +12,7 @@ #include "db/Db.hpp" #include "db/Startup_Strings.hpp" #include "glue/CGlueMgr.hpp" +#include "glue/CCharacterComponent.hpp" #include "gameui/CGGameUI.hpp" #include "gx/Screen.hpp" #include "gx/Texture.hpp" @@ -736,8 +737,8 @@ void WowClientInit() { // TODO // sub_6F75E0(); - // sub_401FF0(); + CCharacterComponent::Initialize(); ClientServices::Initialize(); // TODO ClientServices::SetMessageHandler(SMSG_TUTORIAL_FLAGS, (int)sub_530920, 0); diff --git a/src/glue/CCharacterComponent.cpp b/src/glue/CCharacterComponent.cpp index 07dc44f..448ed19 100644 --- a/src/glue/CCharacterComponent.cpp +++ b/src/glue/CCharacterComponent.cpp @@ -1 +1,136 @@ #include "glue/CCharacterComponent.hpp" + +#include + +#include +#include +#include "console/Types.hpp" +#include "console/CVar.hpp" + +CVar* CCharacterComponent::g_componentTextureLevelVar = nullptr; +CVar* CCharacterComponent::g_componentThreadVar = nullptr; +CVar* CCharacterComponent::g_componentCompressVar = nullptr; + +uint32_t* CCharacterComponent::s_heap = nullptr; + + +static bool ComponentVarHandler(CVar*, const char*, const char*, void*) { + return true; +} + +ComponentData::ComponentData() { + this->m_unkFlag &= 0xFFFFFFFC; + memset(&this->m_info, 0, sizeof(this->m_info)); + this->m_model = nullptr; +} + +void CCharacterComponent::Initialize() { + CCharacterComponent::g_componentTextureLevelVar = CVar::Register( + "componentTextureLevel", + "Number of mip levels used for character component textures", + 0x1, + "8", + &ComponentVarHandler, + CATEGORY::DEBUG, + 0, + nullptr, + false); + + CCharacterComponent::g_componentThreadVar = CVar::Register( + "componentThread", + "Multi thread character component processing", + 0x1, + "1", + &ComponentVarHandler, + CATEGORY::DEBUG, + 0, + nullptr, + false); + + CCharacterComponent::g_componentCompressVar = CVar::Register( + "componentCompress", + "Character component texture compression", + 0x1, + "1", + &ComponentVarHandler, + CATEGORY::DEBUG, + 0, + nullptr, + false); + + uint32_t mipLevels = CCharacterComponent::g_componentTextureLevelVar->GetInt(); + int32_t useThreads = CCharacterComponent::g_componentThreadVar->GetInt(); + int32_t useCompression = CCharacterComponent::g_componentCompressVar->GetInt(); + + if (!useThreads || OsGetProcessorCount() < 2) { + useThreads = 0; + + if (mipLevels > 8) { + mipLevels = 8; + } + + useCompression = 0; + } + + if (mipLevels > 9) { + mipLevels = 9; + } + + if (mipLevels < 7) { + mipLevels = 7; + } + + CCharacterComponent::Initialize(GxTex_Rgb565, mipLevels, useThreads, useCompression); +} + +void CCharacterComponent::Initialize(EGxTexFormat format, uint32_t mipLevels, int32_t useThreads, int32_t useCompression) { + CCharacterComponent::s_heap = static_cast(ALLOC(sizeof(uint32_t))); + if (CCharacterComponent::s_heap) { + *CCharacterComponent::s_heap = ObjectAllocAddHeap(sizeof(CCharacterComponent), 32, "CCharacterComponent", true); + } + + // TODO +} + +CCharacterComponent* CCharacterComponent::AllocComponent() { + + uint32_t handle; + void* memory; + + if (ObjectAlloc(*CCharacterComponent::s_heap, &handle, &memory, false) && memory) { + auto component = new (memory) CCharacterComponent(); + component->m_handle = handle; + return component; + } + return nullptr; +} + +void CCharacterComponent::FreeComponent(CCharacterComponent* component) { + component->~CCharacterComponent(); + // TODO: ObjectFree() +} + +CCharacterComponent::CCharacterComponent() { +} + +CCharacterComponent::~CCharacterComponent() { +} + +void CCharacterComponent::SetRandomSkin(COMPONENT_CONTEXT context) { +} + +void CCharacterComponent::SetRandomHairColor(COMPONENT_CONTEXT context) { +} + +void CCharacterComponent::SetRandomHairStyle(COMPONENT_CONTEXT context) { +} + +void CCharacterComponent::SetRandomFace(COMPONENT_CONTEXT context) { +} + +void CCharacterComponent::SetRandomFacialFeature(COMPONENT_CONTEXT context) { +} + +bool CCharacterComponent::Init(ComponentData* data, const char* a3) { + return false; +} diff --git a/src/glue/CCharacterComponent.hpp b/src/glue/CCharacterComponent.hpp index 22601dd..e4d27da 100644 --- a/src/glue/CCharacterComponent.hpp +++ b/src/glue/CCharacterComponent.hpp @@ -2,16 +2,61 @@ #define GLUE_C_CHARACTER_COMPONENT_HPP #include "net/Types.hpp" +#include "gx/Types.hpp" #include class CSimpleModelFFX; class CM2Model; +class CVar; + +class ComponentData { + public: + ComponentData(); + + public: + CHARACTER_CREATE_INFO m_info; + CM2Model* m_model; + uint32_t m_unkFlag; +}; class CCharacterComponent { + public: + enum COMPONENT_CONTEXT + { + DEFAULT_CONTEXT = 0, + CONTEXT_1, + CONTEXT_2, + CONTEXT_3 + }; + public: // Static variables + static CVar* g_componentTextureLevelVar; + static CVar* g_componentThreadVar; + static CVar* g_componentCompressVar; + + static uint32_t* s_heap; // Static functions + static void Initialize(); + static void Initialize(EGxTexFormat format, uint32_t mipLevels, int32_t useThreads, int32_t useCompression); + static CCharacterComponent* AllocComponent(); + static void FreeComponent(CCharacterComponent* component); + + CCharacterComponent(); + ~CCharacterComponent(); + + void SetRandomSkin(COMPONENT_CONTEXT context = DEFAULT_CONTEXT); + void SetRandomHairColor(COMPONENT_CONTEXT context = DEFAULT_CONTEXT); + void SetRandomHairStyle(COMPONENT_CONTEXT context = DEFAULT_CONTEXT); + void SetRandomFace(COMPONENT_CONTEXT context = DEFAULT_CONTEXT); + void SetRandomFacialFeature(COMPONENT_CONTEXT context = DEFAULT_CONTEXT); + + bool Init(ComponentData* data, const char* a3); + + public: + uint32_t m_handle; + ComponentData m_data; }; #endif // GLUE_C_CHARACTER_COMPONENT_HPP diff --git a/src/glue/CCharacterCreation.cpp b/src/glue/CCharacterCreation.cpp index a175055..29877ee 100644 --- a/src/glue/CCharacterCreation.cpp +++ b/src/glue/CCharacterCreation.cpp @@ -1,8 +1,114 @@ #include "glue/CCharacterCreation.hpp" +#include "glue/CCharacterComponent.hpp" +#include "ui/CSimpleModelFFX.hpp" +#include "model/CM2Model.hpp" +#include "clientobject/Player_C.hpp" +#include "db/Db.hpp" -float CCharacterCreation::m_charFacing = 0.0; -CharacterCreationDisplay CCharacterCreation::m_character = {}; +int32_t CCharacterCreation::m_existingCharacterIndex; +int32_t CCharacterCreation::m_raceIndex; +CSimpleModel* CCharacterCreation::m_charCustomizeFrame; +float CCharacterCreation::m_charFacing; +uint32_t CCharacterCreation::m_prevSkinIndex; +uint32_t CCharacterCreation::m_prevFaceIndex; +uint32_t CCharacterCreation::m_prevHairColorIndex; +uint32_t CCharacterCreation::m_prevHairStyleIndex; +uint32_t CCharacterCreation::m_prevFacialFeatureIndex; +CCharacterComponent* CCharacterCreation::m_character = nullptr; +TSGrowableArray CCharacterCreation::m_races; void CCharacterCreation::Initialize() { CCharacterCreation::m_charFacing = 0.0; + CCharacterCreation::m_charCustomizeFrame = nullptr; + CCharacterCreation::m_existingCharacterIndex = -1; +} + +void CCharacterCreation::SetCharCustomizeFrame(CSimpleModel* frame) { + CCharacterCreation::m_charCustomizeFrame = frame; +} + +void CCharacterCreation::SetCharCustomizeModel(char const* filename) { + if (!CCharacterCreation::m_charCustomizeFrame || !filename || !*filename) { + return; + } + + // TODO + CCharacterCreation::m_charCustomizeFrame->SetModel(filename); +} + +void CCharacterCreation::ResetCharCustomizeInfo() { + if (!CCharacterCreation::m_charCustomizeFrame) { + return; + } + + CCharacterCreation::m_existingCharacterIndex = -1; + + // TODO: CM2Model__DetachAllChildrenById + + ComponentData data; + CCharacterCreation::GetRandomRaceAndSex(&data); + CCharacterCreation::CalcClasses(data.m_info.raceID); + CCharacterCreation::InitCharacterComponent(&data, 1); + + // TODO + + CCharacterCreation::m_raceIndex = -1; + + // TODO +} + +void CCharacterCreation::GetRandomRaceAndSex(ComponentData* data) { + // TODO + // WORKAROUND + data->m_info.raceID = 1; +} + +void CCharacterCreation::CalcClasses(uint32_t raceID) { +} + +void CCharacterCreation::InitCharacterComponent(ComponentData* data, int32_t randomize) { + auto record = Player_C_GetModelName(data->m_info.raceID, data->m_info.sexID); + if (!record || !record->m_modelName[0]) { + return; + } + + if (CCharacterCreation::m_character) { + auto model = CCharacterCreation::m_character->m_data.m_model; + if (model->m_attachParent) { + // TODO: model->DetachFromParent(); + } + CCharacterComponent::FreeComponent(CCharacterCreation::m_character); + } + + CCharacterCreation::m_character = CCharacterComponent::AllocComponent(); + + auto scene = CCharacterCreation::m_charCustomizeFrame->GetScene(); + data->m_model = scene->CreateModel(record->m_modelName, 0); + if (!data->m_model) { + return; + } + + data->m_unkFlag |= 2u; + CCharacterCreation::m_character->Init(data, nullptr); + + if (randomize) { + CCharacterCreation::RandomizeCharFeatures(); + } + + // TODO +} + +void CCharacterCreation::RandomizeCharFeatures() { + CCharacterCreation::m_character->SetRandomSkin(); + CCharacterCreation::m_character->SetRandomHairColor(); + CCharacterCreation::m_character->SetRandomHairStyle(); + CCharacterCreation::m_character->SetRandomFace(); + CCharacterCreation::m_character->SetRandomFacialFeature(); + + const auto& info = CCharacterCreation::m_character->m_data.m_info; + CCharacterCreation::m_prevSkinIndex = info.skinID; + CCharacterCreation::m_prevFaceIndex = info.faceID; + CCharacterCreation::m_prevHairColorIndex = info.hairColorID; + CCharacterCreation::m_prevHairStyleIndex = info.hairStyleID; + CCharacterCreation::m_prevFacialFeatureIndex = info.facialFeatureID; } diff --git a/src/glue/CCharacterCreation.hpp b/src/glue/CCharacterCreation.hpp index d48ad6d..79a2d22 100644 --- a/src/glue/CCharacterCreation.hpp +++ b/src/glue/CCharacterCreation.hpp @@ -4,22 +4,37 @@ #include "net/Types.hpp" #include +class CSimpleModel; class CSimpleModelFFX; class CM2Model; +class ComponentData; +class CCharacterComponent; -struct CharacterCreationDisplay { - CHARACTER_CREATE_INFO m_characterInfo; - CM2Model* m_characterModel; -}; class CCharacterCreation { public: // Static variables + static int32_t m_existingCharacterIndex; + static int32_t m_raceIndex; + static CSimpleModel* m_charCustomizeFrame; static float m_charFacing; - static CharacterCreationDisplay m_character; + static uint32_t m_prevSkinIndex; + static uint32_t m_prevFaceIndex; + static uint32_t m_prevHairColorIndex; + static uint32_t m_prevHairStyleIndex; + static uint32_t m_prevFacialFeatureIndex; + static CCharacterComponent* m_character; + static TSGrowableArray m_races; // Static functions static void Initialize(); + static void SetCharCustomizeFrame(CSimpleModel* frame); + static void SetCharCustomizeModel(char const* filename); + static void ResetCharCustomizeInfo(); + static void GetRandomRaceAndSex(ComponentData* data); + static void CalcClasses(uint32_t raceID); + static void InitCharacterComponent(ComponentData* data, int32_t randomize); + static void RandomizeCharFeatures(); }; #endif // GLUE_C_CHARACTER_CREATION_HPP diff --git a/src/glue/CGlueMgr.cpp b/src/glue/CGlueMgr.cpp index 25cd17b..5d92581 100644 --- a/src/glue/CGlueMgr.cpp +++ b/src/glue/CGlueMgr.cpp @@ -813,15 +813,12 @@ void CGlueMgr::InitCursor() { } void CGlueMgr::Resume() { - // TODO - // CGlueMgr::m_disconnectPending = 0; - // CGlueMgr::m_reconnect = 0; - + CGlueMgr::m_disconnectPending = 0; + CGlueMgr::m_reconnect = 0; CGlueMgr::m_idleState = IDLE_NONE; + CGlueMgr::m_showedDisconnect = 0; - // TODO - // CGlueMgr::m_showedDisconnect = 0; - // CGlueMgr::m_characterInfo = 0; + CGlueMgr::m_characterInfo = nullptr; CGlueMgr::m_suspended = 0; CGlueMgr::m_reload = 0; diff --git a/src/net/Types.hpp b/src/net/Types.hpp index bd65e34..35c58f3 100644 --- a/src/net/Types.hpp +++ b/src/net/Types.hpp @@ -1287,9 +1287,14 @@ struct CHARACTER_INFO { }; struct CHARACTER_CREATE_INFO { - uint8_t unk[24]; uint32_t raceID; uint32_t sexID; + uint32_t unk; + uint32_t hairColorID; + uint32_t skinID; + uint32_t faceID; + uint32_t facialFeatureID; + uint32_t hairStyleID; }; struct CLIENT_NETSTATS { diff --git a/src/ui/ScriptFunctionsCharCreate.cpp b/src/ui/ScriptFunctionsCharCreate.cpp index 2f49eb6..3e91140 100644 --- a/src/ui/ScriptFunctionsCharCreate.cpp +++ b/src/ui/ScriptFunctionsCharCreate.cpp @@ -1,27 +1,49 @@ #include "ui/ScriptFunctions.hpp" +#include "ui/CSimpleModelFFX.hpp" #include "ui/Types.hpp" #include "util/Lua.hpp" #include "util/Unimplemented.hpp" #include "db/Db.hpp" #include "clientobject/Unit_C.hpp" #include "glue/CCharacterCreation.hpp" +#include "glue/CCharacterComponent.hpp" #include int32_t Script_SetCharCustomizeFrame(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isstring(L, 1)) { + return luaL_error(L, "Usage: SetCharCustomizeFrame(\"frameName\")"); + } + + auto type = CSimpleModel::GetObjectType(); + auto name = lua_tolstring(L, 1, nullptr); + auto frame = CScriptObject::GetScriptObjectByName(name, type); + + if (frame) { + CCharacterCreation::SetCharCustomizeFrame(static_cast(frame)); + } + + return 0; } int32_t Script_SetCharCustomizeBackground(lua_State* L) { - WHOA_UNIMPLEMENTED(0); + if (!lua_isstring(L, 1)) { + return luaL_error(L, "Usage: SetCharCustomizeBackground(\"filename\")"); + } + + auto filename = lua_tolstring(L, 1, nullptr); + CCharacterCreation::SetCharCustomizeModel(filename); + + return 0; } -int32_t Script_ResetCharCustomize(lua_State* L) { - WHOA_UNIMPLEMENTED(0); +int32_t Script_ResetCharCustomize(lua_State*) { + CCharacterCreation::ResetCharCustomizeInfo(); + return 0; } int32_t Script_GetNameForRace(lua_State* L) { - auto raceID = CCharacterCreation::m_character.m_characterInfo.raceID; - auto sexID = CCharacterCreation::m_character.m_characterInfo.sexID; + auto raceID = CCharacterCreation::m_character->m_data.m_info.raceID; + auto sexID = CCharacterCreation::m_character->m_data.m_info.sexID; auto record = g_chrRacesDB.GetRecord(raceID); auto raceName = CGUnit_C::GetDisplayRaceNameFromRecord(record, sexID); if (record && raceName) {