Compare commits

...

3 Commits

8 changed files with 493 additions and 26 deletions

View File

@ -12,6 +12,7 @@
#include "db/Db.hpp" #include "db/Db.hpp"
#include "db/Startup_Strings.hpp" #include "db/Startup_Strings.hpp"
#include "glue/CGlueMgr.hpp" #include "glue/CGlueMgr.hpp"
#include "glue/CCharacterComponent.hpp"
#include "gameui/CGGameUI.hpp" #include "gameui/CGGameUI.hpp"
#include "gx/Screen.hpp" #include "gx/Screen.hpp"
#include "gx/Texture.hpp" #include "gx/Texture.hpp"
@ -736,8 +737,8 @@ void WowClientInit() {
// TODO // TODO
// sub_6F75E0(); // sub_6F75E0();
// sub_401FF0();
CCharacterComponent::Initialize();
ClientServices::Initialize(); ClientServices::Initialize();
// TODO ClientServices::SetMessageHandler(SMSG_TUTORIAL_FLAGS, (int)sub_530920, 0); // TODO ClientServices::SetMessageHandler(SMSG_TUTORIAL_FLAGS, (int)sub_530920, 0);

View File

@ -1 +1,137 @@
#include "glue/CCharacterComponent.hpp" #include "glue/CCharacterComponent.hpp"
#include <algorithm>
#include <common/ObjectAlloc.hpp>
#include <common/Processor.hpp>
#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<uint32_t*>(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) {
this->m_data = *data;
return false;
}

View File

@ -2,16 +2,61 @@
#define GLUE_C_CHARACTER_COMPONENT_HPP #define GLUE_C_CHARACTER_COMPONENT_HPP
#include "net/Types.hpp" #include "net/Types.hpp"
#include "gx/Types.hpp"
#include <storm/Array.hpp> #include <storm/Array.hpp>
class CSimpleModelFFX; class CSimpleModelFFX;
class CM2Model; class CM2Model;
class CVar;
class ComponentData {
public:
ComponentData();
public:
CHARACTER_CREATE_INFO m_info;
CM2Model* m_model;
uint32_t m_unkFlag;
};
class CCharacterComponent { class CCharacterComponent {
public:
enum COMPONENT_CONTEXT
{
DEFAULT_CONTEXT = 0,
CONTEXT_1,
CONTEXT_2,
CONTEXT_3
};
public: public:
// Static variables // Static variables
static CVar* g_componentTextureLevelVar;
static CVar* g_componentThreadVar;
static CVar* g_componentCompressVar;
static uint32_t* s_heap;
// Static functions // 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 #endif // GLUE_C_CHARACTER_COMPONENT_HPP

View File

@ -1,8 +1,178 @@
#include "glue/CCharacterCreation.hpp" #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; int32_t CCharacterCreation::m_existingCharacterIndex;
CharacterCreationDisplay CCharacterCreation::m_character = {}; 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<ChrClassesRec*> CCharacterCreation::m_classes;
TSGrowableArray<int32_t> CCharacterCreation::m_races;
void CCharacterCreation::Initialize() { void CCharacterCreation::Initialize() {
CCharacterCreation::m_charFacing = 0.0; CCharacterCreation::m_charFacing = 0.0;
int32_t factionSwitch = 0;
CCharacterCreation::m_charCustomizeFrame = nullptr;
CCharacterCreation::m_existingCharacterIndex = -1;
// TODO: memset
int32_t factionSwitch2 = 0;
bool weirdCondition = false;
do {
for (int32_t raceIndex = 0; raceIndex < g_chrRacesDB.GetNumRecords(); ++raceIndex) {
auto raceRecord = g_chrRacesDB.GetRecordByIndex(raceIndex);
if (!raceRecord || (raceRecord->m_flags & 1) != 0) {
continue;
}
auto factionTemplateRecord = g_factionTemplateDB.GetRecord(raceRecord->m_factionID);
if (!factionTemplateRecord) {
continue;
}
for (int32_t factionGroupIndex = 0; factionGroupIndex < g_factionGroupDB.GetNumRecords(); ++factionGroupIndex) {
auto factionGroupRecord = g_factionGroupDB.GetRecordByIndex(factionGroupIndex);
if (!factionGroupRecord || factionGroupRecord->m_maskID == 0) {
continue;
}
if (((1 << factionGroupRecord->m_maskID) & factionTemplateRecord->m_factionGroup) == 0) {
continue;
}
if (SStrCmpI(factionGroupRecord->m_internalName, factionSwitch == 1 ? "Horde" : "Alliance", STORM_MAX_STR)) {
continue;
}
CCharacterCreation::m_races.Add(1, &raceRecord->m_ID);
factionSwitch = factionSwitch2;
}
}
weirdCondition = factionSwitch++ == -1;
factionSwitch2 = factionSwitch;
} while (weirdCondition || factionSwitch == 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) {
uint32_t count = 0;
for (int32_t i = 0; i < g_charBaseInfoDB.GetNumRecords(); ++i) {
auto record = g_charBaseInfoDB.GetRecordByIndex(i);
if (record && record->m_raceID == raceID) {
++count;
}
}
CCharacterCreation::m_classes.SetCount(count);
uint32_t index = 0;
for (int32_t i = 0; i < g_charBaseInfoDB.GetNumRecords(); ++i) {
auto record = g_charBaseInfoDB.GetRecordByIndex(i);
if (!record || record->m_raceID != raceID) {
continue;
}
CCharacterCreation::m_classes[index] = g_chrClassesDB.GetRecord(record->m_classID);
++index;
}
}
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;
} }

View File

@ -4,22 +4,39 @@
#include "net/Types.hpp" #include "net/Types.hpp"
#include <storm/Array.hpp> #include <storm/Array.hpp>
class CSimpleModel;
class CSimpleModelFFX; class CSimpleModelFFX;
class CM2Model; class CM2Model;
class ComponentData;
class CCharacterComponent;
class ChrClassesRec;
struct CharacterCreationDisplay {
CHARACTER_CREATE_INFO m_characterInfo;
CM2Model* m_characterModel;
};
class CCharacterCreation { class CCharacterCreation {
public: public:
// Static variables // Static variables
static int32_t m_existingCharacterIndex;
static int32_t m_raceIndex;
static CSimpleModel* m_charCustomizeFrame;
static float m_charFacing; 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<ChrClassesRec*> m_classes;
static TSGrowableArray<int32_t> m_races;
// Static functions // Static functions
static void Initialize(); 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 #endif // GLUE_C_CHARACTER_CREATION_HPP

View File

@ -813,15 +813,12 @@ void CGlueMgr::InitCursor() {
} }
void CGlueMgr::Resume() { void CGlueMgr::Resume() {
// TODO CGlueMgr::m_disconnectPending = 0;
// CGlueMgr::m_disconnectPending = 0; CGlueMgr::m_reconnect = 0;
// CGlueMgr::m_reconnect = 0;
CGlueMgr::m_idleState = IDLE_NONE; CGlueMgr::m_idleState = IDLE_NONE;
CGlueMgr::m_showedDisconnect = 0;
// TODO CGlueMgr::m_characterInfo = nullptr;
// CGlueMgr::m_showedDisconnect = 0;
// CGlueMgr::m_characterInfo = 0;
CGlueMgr::m_suspended = 0; CGlueMgr::m_suspended = 0;
CGlueMgr::m_reload = 0; CGlueMgr::m_reload = 0;

View File

@ -1287,9 +1287,14 @@ struct CHARACTER_INFO {
}; };
struct CHARACTER_CREATE_INFO { struct CHARACTER_CREATE_INFO {
uint8_t unk[24];
uint32_t raceID; uint32_t raceID;
uint32_t sexID; uint32_t sexID;
uint32_t unk;
uint32_t hairColorID;
uint32_t skinID;
uint32_t faceID;
uint32_t facialFeatureID;
uint32_t hairStyleID;
}; };
struct CLIENT_NETSTATS { struct CLIENT_NETSTATS {

View File

@ -1,27 +1,49 @@
#include "ui/ScriptFunctions.hpp" #include "ui/ScriptFunctions.hpp"
#include "ui/CSimpleModelFFX.hpp"
#include "ui/Types.hpp" #include "ui/Types.hpp"
#include "util/Lua.hpp" #include "util/Lua.hpp"
#include "util/Unimplemented.hpp" #include "util/Unimplemented.hpp"
#include "db/Db.hpp" #include "db/Db.hpp"
#include "clientobject/Unit_C.hpp" #include "clientobject/Unit_C.hpp"
#include "glue/CCharacterCreation.hpp" #include "glue/CCharacterCreation.hpp"
#include "glue/CCharacterComponent.hpp"
#include <cstdint> #include <cstdint>
int32_t Script_SetCharCustomizeFrame(lua_State* L) { 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<CSimpleModel*>(frame));
}
return 0;
} }
int32_t Script_SetCharCustomizeBackground(lua_State* L) { int32_t Script_SetCharCustomizeBackground(lua_State* L) {
WHOA_UNIMPLEMENTED(0); if (!lua_isstring(L, 1)) {
return luaL_error(L, "Usage: SetCharCustomizeBackground(\"filename\")");
} }
int32_t Script_ResetCharCustomize(lua_State* L) { auto filename = lua_tolstring(L, 1, nullptr);
WHOA_UNIMPLEMENTED(0); CCharacterCreation::SetCharCustomizeModel(filename);
return 0;
}
int32_t Script_ResetCharCustomize(lua_State*) {
CCharacterCreation::ResetCharCustomizeInfo();
return 0;
} }
int32_t Script_GetNameForRace(lua_State* L) { int32_t Script_GetNameForRace(lua_State* L) {
auto raceID = CCharacterCreation::m_character.m_characterInfo.raceID; auto raceID = CCharacterCreation::m_character->m_data.m_info.raceID;
auto sexID = CCharacterCreation::m_character.m_characterInfo.sexID; auto sexID = CCharacterCreation::m_character->m_data.m_info.sexID;
auto record = g_chrRacesDB.GetRecord(raceID); auto record = g_chrRacesDB.GetRecord(raceID);
auto raceName = CGUnit_C::GetDisplayRaceNameFromRecord(record, sexID); auto raceName = CGUnit_C::GetDisplayRaceNameFromRecord(record, sexID);
if (record && raceName) { if (record && raceName) {
@ -36,19 +58,93 @@ int32_t Script_GetNameForRace(lua_State* L) {
} }
int32_t Script_GetFactionForRace(lua_State* L) { int32_t Script_GetFactionForRace(lua_State* L) {
WHOA_UNIMPLEMENTED(0); if (!lua_isnumber(L, 1)) {
return luaL_error(L, "Usage: GetFactionForRace(index)");
}
uint32_t index = static_cast<uint32_t>(lua_tonumber(L, 1)) - 1;
int32_t raceID = 0;
if (index < CCharacterCreation::m_races.Count()) {
raceID = CCharacterCreation::m_races[index];
}
auto raceRecord = g_chrRacesDB.GetRecord(raceID);
if (raceRecord) {
auto factionTemplateRecord = g_factionTemplateDB.GetRecord(raceRecord->m_factionID);
if (factionTemplateRecord) {
for (int32_t i = 0; i < g_factionGroupDB.GetNumRecords(); ++i) {
auto factionGroupRecord = g_factionGroupDB.GetRecordByIndex(i);
if (!factionGroupRecord || factionGroupRecord->m_maskID == 0) {
continue;
}
if (((1 << factionGroupRecord->m_maskID) & factionTemplateRecord->m_factionGroup) != 0) {
lua_pushstring(L, factionGroupRecord->m_name);
lua_pushstring(L, factionGroupRecord->m_internalName);
return 2;
}
}
}
}
lua_pushnil(L);
lua_pushnil(L);
return 2;
} }
int32_t Script_GetAvailableRaces(lua_State* L) { int32_t Script_GetAvailableRaces(lua_State* L) {
WHOA_UNIMPLEMENTED(0); for (uint32_t i = 0; i < CCharacterCreation::m_races.Count(); ++i) {
auto raceRecord = g_chrRacesDB.GetRecord(CCharacterCreation::m_races[i]);
auto raceName = CGUnit_C::GetDisplayRaceNameFromRecord(
raceRecord,
CCharacterCreation::m_character->m_data.m_info.sexID);
lua_pushstring(L, raceName);
lua_pushstring(L, raceRecord ? raceRecord->m_clientFileString : nullptr);
// TODO: Expansion Check
lua_pushnumber(L, 1.0);
}
return CCharacterCreation::m_races.Count() * 3;
} }
int32_t Script_GetAvailableClasses(lua_State* L) { int32_t Script_GetAvailableClasses(lua_State* L) {
WHOA_UNIMPLEMENTED(0); for (int32_t i = 0; i < g_chrClassesDB.GetNumRecords(); ++i) {
auto record = g_chrClassesDB.GetRecordByIndex(i);
auto className = CGUnit_C::GetDisplayClassNameFromRecord(
record,
CCharacterCreation::m_character->m_data.m_info.sexID);
if (className) {
lua_pushstring(L, className);
lua_pushstring(L, record->m_filename);
// TODO: Expansion Check
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
lua_pushnil(L);
lua_pushnil(L);
}
}
return g_chrClassesDB.GetNumRecords() * 3;
} }
int32_t Script_GetClassesForRace(lua_State* L) { int32_t Script_GetClassesForRace(lua_State* L) {
WHOA_UNIMPLEMENTED(0); for (uint32_t i = 0; i < CCharacterCreation::m_classes.Count(); ++i) {
auto record = CCharacterCreation::m_classes[i];
auto className = CGUnit_C::GetDisplayClassNameFromRecord(
record,
CCharacterCreation::m_character->m_data.m_info.sexID);
if (className) {
lua_pushstring(L, className);
lua_pushstring(L, record->m_filename);
// TODO: Expansion Check
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
lua_pushnil(L);
lua_pushnil(L);
}
}
return CCharacterCreation::m_classes.Count() * 3;
} }
int32_t Script_GetHairCustomization(lua_State* L) { int32_t Script_GetHairCustomization(lua_State* L) {