* update gui charlist when crating a char

* implemented display correct response string in console & gui if char creation failed
* fixed & simplified PlayerNameCache, load directly before world join and not at charlist receive
* fixed some warnings
* misc stuff
* TODO: fix bug that prevents reopening char create window after creating char + implement dixplaying response strings for actions other then char creation.
This commit is contained in:
false_genesis 2009-04-25 20:20:28 +00:00
parent 585046fce2
commit 2b1d743125
13 changed files with 300 additions and 127 deletions

View File

@ -15,3 +15,6 @@
0=Realmlist 0=Realmlist
1=Create New Character 1=Create New Character
[3]
0=Creating new Character...

View File

@ -36,6 +36,9 @@ LoadDB sound
LoadDB gui_login_text LoadDB gui_login_text
LoadDB gui_charselect_text LoadDB gui_charselect_text
// misc data
LoadDB generic_text
log ** Databases loaded. log ** Databases loaded.

View File

@ -60,10 +60,11 @@ Scene::~Scene()
DEBUG(logdebug("Scene::~Scene()")); DEBUG(logdebug("Scene::~Scene()"));
} }
core::stringw Scene::GetStringFromDB(u32 index, u32 entry) core::stringw Scene::GetStringFromDB(u32 index, u32 entry, SCPDatabase *other_db /* = NULL */)
{ {
core::stringw r = ""; core::stringw r = "";
if(!textdb) SCPDatabase *db = other_db ? other_db : textdb;
if(!db)
{ {
r += L"<string "; r += L"<string ";
r += index; r += index;
@ -74,6 +75,6 @@ core::stringw Scene::GetStringFromDB(u32 index, u32 entry)
} }
char buf[20]; char buf[20];
sprintf(buf,"%u",entry); sprintf(buf,"%u",entry);
r += textdb->GetString(index, buf); r += db->GetString(index, buf);
return r; return r;
} }

View File

@ -39,7 +39,7 @@ class Scene
public: public:
Scene(PseuGUI *g); Scene(PseuGUI *g);
~Scene(); ~Scene();
core::stringw GetStringFromDB(u32 index, u32 entry); core::stringw GetStringFromDB(u32 index, u32 entry, SCPDatabase *other_db = NULL);
inline void SetState(SceneState sc) { _scenestate = sc; } inline void SetState(SceneState sc) { _scenestate = sc; }
inline SceneState GetState(void) { return _scenestate; } inline SceneState GetState(void) { return _scenestate; }
virtual void OnUpdate(s32); virtual void OnUpdate(s32);
@ -99,9 +99,12 @@ class SceneCharSelection : public Scene
public: public:
SceneCharSelection(PseuGUI *gui); SceneCharSelection(PseuGUI *gui);
void OnUpdate(s32); void OnUpdate(s32);
void OnManualUpdate(void);
void OnDelete(void); void OnDelete(void);
void OnResize(void); void OnResize(void);
void FillCharlist(void);
private: private:
GUIEventReceiver *eventrecv; GUIEventReceiver *eventrecv;
IGUIWindow *realmwin; IGUIWindow *realmwin;
@ -112,6 +115,8 @@ private:
IGUIComboBox *raceselect; IGUIComboBox *raceselect;
IGUIComboBox *classselect; IGUIComboBox *classselect;
IGUIEditBox *charname; IGUIEditBox *charname;
IGUIElement *msgbox; // display status/result of character creation
uint32 msgbox_textid; // stores old textid
std::map<u32,u32> racemap, classmap; //<comboBoxId,dbId> maps DB IDs in db to IDs in the combobox, because irrlicht does not allow custom ids in comboboxes std::map<u32,u32> racemap, classmap; //<comboBoxId,dbId> maps DB IDs in db to IDs in the combobox, because irrlicht does not allow custom ids in comboboxes
}; };

View File

@ -50,7 +50,22 @@ SceneCharSelection::SceneCharSelection(PseuGUI *gui) : Scene(gui)
rect<s32> clb_rect = CalcRelativeScreenPos(driver, 0.65f, 0.12f, 0.34f, 0.67f); rect<s32> clb_rect = CalcRelativeScreenPos(driver, 0.65f, 0.12f, 0.34f, 0.67f);
charlistbox = guienv->addListBox(clb_rect); charlistbox = guienv->addListBox(clb_rect);
mutex.acquire(); FillCharlist();
if(soundengine)
{
ISoundSource *main_theme = soundengine->getSoundSource("data/misc/main_theme.ogg");
if(main_theme && !soundengine->isCurrentlyPlaying(main_theme))
{
soundengine->play2D(main_theme,true);
}
}
}
void SceneCharSelection::FillCharlist(void)
{
ZThread::Guard<ZThread::FastMutex> g(mutex);
charlistbox->clear();
WorldSession *ws = instance->GetWSession(); WorldSession *ws = instance->GetWSession();
if(ws) if(ws)
{ {
@ -88,16 +103,6 @@ SceneCharSelection::SceneCharSelection(PseuGUI *gui) : Scene(gui)
} }
} }
mutex.release();
if(soundengine)
{
ISoundSource *main_theme = soundengine->getSoundSource("data/misc/main_theme.ogg");
if(main_theme && !soundengine->isCurrentlyPlaying(main_theme))
{
soundengine->play2D(main_theme,true);
}
}
} }
void SceneCharSelection::OnUpdate(s32 timepassed) void SceneCharSelection::OnUpdate(s32 timepassed)
@ -182,10 +187,11 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
{ {
guienv->addMessageBox(L"Not yet implemented!", L"Deleting a character does not yet work!"); guienv->addMessageBox(L"Not yet implemented!", L"Deleting a character does not yet work!");
} }
if(eventrecv->buttons & BUTTON_NEW_CHARACTER) if(eventrecv->buttons & BUTTON_NEW_CHARACTER && !newcharwin)
{ {
dimension2d<s32> dim; dimension2d<s32> dim;
rect<s32> pos; rect<s32> pos;
msgbox_textid = 0;
newcharwin = guienv->addWindow(CalcRelativeScreenPos(driver, 0.2f, 0.2f, 0.6f, 0.6f), true, newcharwin = guienv->addWindow(CalcRelativeScreenPos(driver, 0.2f, 0.2f, 0.6f, 0.6f), true,
GetStringFromDB(ISCENE_CHARSEL_LABELS, DSCENE_CHARSEL_LABEL_NEWCHARWIN).c_str()); GetStringFromDB(ISCENE_CHARSEL_LABELS, DSCENE_CHARSEL_LABEL_NEWCHARWIN).c_str());
pos = newcharwin->getAbsolutePosition(); // get absolute position and transform <dim> to absolute in-window position pos = newcharwin->getAbsolutePosition(); // get absolute position and transform <dim> to absolute in-window position
@ -213,7 +219,7 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
//newcharwin->addChild(classselect); //newcharwin->addChild(classselect);
guienv->addStaticText(L"Char Name", CalcRelativeScreenPos(dim,0.1f,0.3f,0.8f,0.05f),false,true,newcharwin); guienv->addStaticText(L"Char Name", CalcRelativeScreenPos(dim,0.1f,0.3f,0.8f,0.05f),false,true,newcharwin);
charname = guienv->addEditBox(L"", CalcRelativeScreenPos(dim,0.1f,0.35f,0.8f,0.05f),true, newcharwin); charname = guienv->addEditBox(L"", CalcRelativeScreenPos(dim,0.1f,0.35f,0.8f,0.05f),true, newcharwin);
//guienv->addMessageBox(L"Not yet implemented!", L"Creating a new character does not yet work!"); msgbox = guienv->addStaticText(L"",CalcRelativeScreenPos(dim,0.2f,0.6f,0.6f,0.1f), true, true, newcharwin);
} }
if(eventrecv->buttons & BUTTON_SELECT_REALM || scenedata[ISCENE_CHARSEL_REALMFIRST]) if(eventrecv->buttons & BUTTON_SELECT_REALM || scenedata[ISCENE_CHARSEL_REALMFIRST])
{ {
@ -299,21 +305,20 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
if(eventrecv->buttons & BUTTON_NEWCHARWIN_OK && newcharwin) if(eventrecv->buttons & BUTTON_NEWCHARWIN_OK && newcharwin)
{ {
core::stringc tmp=charname->getText(); core::stringc chname = charname->getText();
u8 race = racemap[raceselect->getSelected()]; u8 race = racemap[raceselect->getSelected()];
u8 cclass = classmap[classselect->getSelected()]; u8 cclass = classmap[classselect->getSelected()];
log("Creating character Race %i Class %i Name %s",race,cclass,tmp.c_str()); if(chname.size() && race && cclass)
if(tmp.size() && race && cclass)
{ {
WorldSession *ws=instance->GetWSession(); WorldSession *ws=instance->GetWSession();
if(ws) if(ws)
{ {
WorldPacket packet(CMSG_CHAR_CREATE,(tmp.size()+1)+1+1+1+1+1+1+1+1+1); ws->SendCharCreate(chname.c_str(), race, cclass);
packet<<tmp.c_str();
// name, race, class, gender, skin, face, hairstyle, haircolor, facialhair, outfitID msgbox->setText(GetStringFromDB(3,0).c_str());
packet << race << cclass <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0; msgbox_textid = 0;
ws->AddSendWorldPacket(packet);
eventrecv->buttons |= BUTTON_NEWCHARWIN_CANCEL; // easiest way to close the window without much additional code // do not close window until character created (will when getting response code 0)
} }
else else
logerror("Trying to create new Character, but no WorldSession exists."); logerror("Trying to create new Character, but no WorldSession exists.");
@ -323,7 +328,6 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
} }
// realmlist window // realmlist window
if(eventrecv->buttons & BUTTON_REALMWIN_CANCEL && realmwin) if(eventrecv->buttons & BUTTON_REALMWIN_CANCEL && realmwin)
{ {
realmwin->remove(); realmwin->remove();
@ -337,6 +341,20 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
newcharwin = NULL; newcharwin = NULL;
} }
if(newcharwin && msgbox_textid != scenedata[ISCENE_CHARSEL_ERRMSG])
{
msgbox_textid = scenedata[ISCENE_CHARSEL_ERRMSG];
if(SCPDatabase *generictext = instance->dbmgr.GetDB("generic_text"))
{
msgbox->setText(GetStringFromDB(0, msgbox_textid, generictext).c_str());
}
if(scenedata[ISCENE_CHARSEL_ERRMSG] == CHAR_CREATE_SUCCESS)
{
newcharwin->remove();
newcharwin = NULL;
}
}
eventrecv->buttons = 0; eventrecv->buttons = 0;
} }
@ -351,3 +369,10 @@ void SceneCharSelection::OnResize(void)
} }
// called when receiving SMSG_CHAR_ENUM
void SceneCharSelection::OnManualUpdate(void)
{
Scene::OnManualUpdate();
FillCharlist();
}

View File

@ -49,6 +49,7 @@ enum SceneCharSelectDataIndexes
{ {
ISCENE_CHARSEL_BUTTONS = 1, // text ISCENE_CHARSEL_BUTTONS = 1, // text
ISCENE_CHARSEL_LABELS = 2, // text ISCENE_CHARSEL_LABELS = 2, // text
ISCENE_CHARSEL_ERRMSG = 3, // uint32 response code, see enum ResponseCodes in SharedDefines.h for IDs
ISCENE_CHARSEL_REALMFIRST = 255, // flag that is set when connecting to a realm wasnt possible and the realm list must be shown first ISCENE_CHARSEL_REALMFIRST = 255, // flag that is set when connecting to a realm wasnt possible and the realm list must be shown first
ISCENE_CHARSEL_END ISCENE_CHARSEL_END
}; };
@ -74,4 +75,5 @@ enum SceneCharSelectLabels
#endif #endif

View File

@ -207,5 +207,23 @@ void WorldSession::SendQueryGameobject(uint32 entry, uint64 guid)
SendWorldPacket(wp); SendWorldPacket(wp);
} }
void WorldSession::SendCharCreate(std::string name, uint8 race, uint8 class_, // below here all values default is 0
uint8 gender, uint8 skin, uint8 face,
uint8 hairstyle, uint8 haircolor, uint8 facial, uint8 outfit)
{
log("Creating Character '%s', race=%u, class=%u gender=%u", name.c_str(), race, class_, gender);
WorldPacket wp(CMSG_CHAR_CREATE, name.length()+1 + 9);
wp << name;
wp << race;
wp << class_;
wp << gender;
wp << skin;
wp << face;
wp << hairstyle;
wp << haircolor;
wp << facial;
wp << outfit;
AddSendWorldPacket(wp);
}

View File

@ -17,58 +17,44 @@ uint32 GOTEMPLATES_CACHE_VERSION = 0;
PlayerNameCache::~PlayerNameCache() PlayerNameCache::~PlayerNameCache()
{ {
for(std::vector<PlayerNameCacheItem*>::iterator i=_cache.begin(); i!=_cache.end(); i++)
{
delete *i;
}
} }
bool PlayerNameCache::AddInfo(uint64 guid, std::string name){ void PlayerNameCache::Add(uint64 guid, std::string name)
PlayerNameCacheItem *cacheItem=new PlayerNameCacheItem; {
cacheItem->_name=name; _cache.erase(guid); // drop old data if present
cacheItem->_guid=guid; _cache[guid] = name;
return AddInfo(cacheItem);
} }
bool PlayerNameCache::IsKnown(uint64 guid) bool PlayerNameCache::IsKnown(uint64 guid)
{ {
for(std::vector<PlayerNameCacheItem*>::iterator i=_cache.begin(); i!=_cache.end(); i++) PlayerNameMap::iterator it = _cache.find(guid);
if(guid==(*i)->_guid) if(it != _cache.end())
return true; return true;
return false; return false;
} }
bool PlayerNameCache::AddInfo(PlayerNameCacheItem* cacheItem)
{
for(std::vector<PlayerNameCacheItem*>::iterator i=_cache.begin(); i!=_cache.end(); i++)
if(cacheItem->_guid==(*i)->_guid)
{
delete cacheItem;
return false;
}
_cache.push_back(cacheItem);
return true;
}
std::string PlayerNameCache::GetName(uint64 guid) std::string PlayerNameCache::GetName(uint64 guid)
{ {
for(std::vector<PlayerNameCacheItem*>::iterator i=_cache.begin(); i!=_cache.end(); i++) PlayerNameMap::iterator it = _cache.find(guid);
if(guid==(*i)->_guid) if(it != _cache.end())
return (*i)->_name; return it->second;
return ""; return "";
} }
uint64 PlayerNameCache::GetGuid(std::string name) uint64 PlayerNameCache::GetGuid(std::string name)
{ {
for(std::vector<PlayerNameCacheItem*>::iterator i=_cache.begin(); i!=_cache.end(); i++) for(PlayerNameMap::iterator it = _cache.begin(); it != _cache.end(); it++)
if(name==(*i)->_name) if(it->second == name)
return (*i)->_guid; return it->first;
return 0; return 0;
} }
bool PlayerNameCache::SaveToFile(void) bool PlayerNameCache::SaveToFile(void)
{ {
log("Saving PlayerNameCache..."); if(_cache.empty())
return true; // no data to save, so we are fine
logdebug("Saving PlayerNameCache...");
char *fn="./cache/playernames.cache"; char *fn="./cache/playernames.cache";
std::fstream fh; std::fstream fh;
fh.open(fn, std::ios_base::out | std::ios_base::binary); fh.open(fn, std::ios_base::out | std::ios_base::binary);
@ -78,21 +64,22 @@ bool PlayerNameCache::SaveToFile(void)
return false; return false;
} }
uint32 size = _cache.size(); uint32 size = _cache.size();
if(size==0) if(!size)
return false; return false;
uint8 len;
fh.write((char*)&size,sizeof(uint32));
for(std::vector<PlayerNameCacheItem*>::iterator i=_cache.begin(); i!=_cache.end(); i++) fh.write((char*)&size,sizeof(uint32));
ByteBuffer bb;
bb << (uint32)_cache.size();
for(PlayerNameMap::iterator i=_cache.begin(); i!=_cache.end(); i++)
{ {
fh.write( (char*)&((*i)->_guid),sizeof(uint64) ); bb << i->first;
len=(*i)->_name.length(); bb << (uint8)i->second.length();
fh.write( (char*)&len,sizeof(uint8) ); bb.append(i->second.c_str(), i->second.length()); // do not append '\0'
fh.write( (char*)(*i)->_name.c_str(),len );
DEBUG(log( "PlayerNameCache << " I64FMT " -> %s", (*i)->_guid, (*i)->_name.c_str()););
} }
fh.write((char*)bb.contents(), bb.size());
fh.close(); fh.close();
log("PlayerNameCache saved successfully."); logdebug("PlayerNameCache saved successfully.");
return true; return true;
} }
@ -102,30 +89,32 @@ bool PlayerNameCache::ReadFromFile(void)
log("Loading PlayerNameCache..."); log("Loading PlayerNameCache...");
bool success=true; bool success=true;
std::fstream fh; std::fstream fh;
fh.open(fn, std::ios_base::in | std::ios_base::binary); uint32 size = GetFileSize(fn);
if(!fh.is_open()) if(!size)
{ {
logerror("PlayerNameCache: Could not open file '%s'!",fn); logerror("PlayerNameCache: Could not open file '%s'!",fn);
return false; return false;
} }
if(fh.eof())
{ // do NOT use MemoryDataHolder, since the file can change during runtime and may be loaded again
logdetail("PlayerNameCache: Can't load empty file '%s'",fn); fh.open(fn, std::ios_base::in | std::ios_base::binary);
return false; ByteBuffer bb;
} bb.resize(size);
uint32 size; fh.read((char*)bb.contents(), size);
fh.read((char*)&size,sizeof(uint32)); fh.close();
std::string tmp;
uint8 len; uint8 len;
char *nameptr=new char[13]; uint32 count;
for(unsigned int i=0;i<size;i++) uint64 guid;
char namebuf[MAX_PLAYERNAME_LENGTH + 1];
bb >> count; // entries count
for(uint32 i = 0; i < count; i++)
{ {
len=255; bb >> guid;
memset(nameptr,0,13); bb >> len;
PlayerNameCacheItem *cacheItem=new PlayerNameCacheItem; if(len > MAX_PLAYERNAME_LENGTH || len < MIN_PLAYERNAME_LENGTH || !guid)
fh.read((char*)&(cacheItem->_guid),sizeof(uint64));
fh.read((char*)&len,sizeof(uint8));
if(len > MAX_PLAYERNAME_LENGTH || len < MIN_PLAYERNAME_LENGTH)
{ {
logerror("PlayerNameCache data seem corrupt [namelength=%d, should be <=%u]",len,MAX_PLAYERNAME_LENGTH); logerror("PlayerNameCache data seem corrupt [namelength=%d, should be <=%u]",len,MAX_PLAYERNAME_LENGTH);
log("-> Clearing cache, creating new."); log("-> Clearing cache, creating new.");
@ -133,18 +122,12 @@ bool PlayerNameCache::ReadFromFile(void)
success = false; success = false;
break; break;
} }
fh.read(nameptr,len); memset(namebuf,0,MAX_PLAYERNAME_LENGTH + 1);
cacheItem->_name=nameptr; bb.read((uint8*)namebuf, len);
AddInfo(cacheItem); Add(guid, namebuf);
printf("\rPlayerNameCache [ %u / %u ] items loaded",i+1,size);
DEBUG(printf( " >> " I64FMT " -> %s\n", cacheItem->_guid, nameptr););
} }
printf("\n");
delete nameptr;
fh.flush();
fh.close();
if(success) if(success)
log("PlayerNameCache successfully loaded."); logdebug("PlayerNameCache successfully loaded.");
return success; return success;
} }
@ -215,7 +198,7 @@ void ItemProtoCache_InsertDataToSession(WorldSession *session)
buf >> proto->Stackable; buf >> proto->Stackable;
buf >> proto->ContainerSlots; buf >> proto->ContainerSlots;
buf >> proto->StatsCount; buf >> proto->StatsCount;
for(int i = 0; i < proto->StatsCount; i++) for(uint32 i = 0; i < proto->StatsCount; i++)
{ {
buf >> proto->ItemStat[i].ItemStatType; buf >> proto->ItemStat[i].ItemStatType;
buf >> proto->ItemStat[i].ItemStatValue; buf >> proto->ItemStat[i].ItemStatValue;
@ -349,7 +332,7 @@ void ItemProtoCache_WriteDataToCache(WorldSession *session)
buf << proto->Stackable; buf << proto->Stackable;
buf << proto->ContainerSlots; buf << proto->ContainerSlots;
buf << proto->StatsCount; buf << proto->StatsCount;
for(int i = 0; i < proto->StatsCount; i++) for(uint32 i = 0; i < proto->StatsCount; i++)
{ {
buf << proto->ItemStat[i].ItemStatType; buf << proto->ItemStat[i].ItemStatType;
buf << proto->ItemStat[i].ItemStatValue; buf << proto->ItemStat[i].ItemStatValue;

View File

@ -1,25 +1,22 @@
#ifndef _CACHEHANDLER_H #ifndef _CACHEHANDLER_H
#define _CACHEHANDLER_H #define _CACHEHANDLER_H
struct PlayerNameCacheItem { typedef std::map<uint64,std::string> PlayerNameMap;
uint64 _guid;
std::string _name;
};
class PlayerNameCache { class PlayerNameCache
{
public: public:
~PlayerNameCache(); ~PlayerNameCache();
std::string GetName(uint64); std::string GetName(uint64);
bool IsKnown(uint64); bool IsKnown(uint64);
uint64 GetGuid(std::string); uint64 GetGuid(std::string);
bool AddInfo(uint64 guid, std::string name); void Add(uint64 guid, std::string name);
bool AddInfo(PlayerNameCacheItem*);
bool SaveToFile(void); bool SaveToFile(void);
bool ReadFromFile(void); bool ReadFromFile(void);
uint32 GetSize(void); uint32 GetSize(void);
private: private:
std::vector<PlayerNameCacheItem*> _cache; PlayerNameMap _cache;
}; };
void ItemProtoCache_InsertDataToSession(WorldSession *session); void ItemProtoCache_InsertDataToSession(WorldSession *session);

View File

@ -40,7 +40,7 @@ void WorldSession::_HandleItemQuerySingleResponseOpcode(WorldPacket& recvPacket)
recvPacket >> proto->Stackable; recvPacket >> proto->Stackable;
recvPacket >> proto->ContainerSlots; recvPacket >> proto->ContainerSlots;
recvPacket >> proto->StatsCount; recvPacket >> proto->StatsCount;
for(int i = 0; i < proto->StatsCount; i++) for(uint32 i = 0; i < proto->StatsCount; i++)
{ {
recvPacket >> proto->ItemStat[i].ItemStatType; recvPacket >> proto->ItemStat[i].ItemStatType;
recvPacket >> proto->ItemStat[i].ItemStatValue; recvPacket >> proto->ItemStat[i].ItemStatValue;

View File

@ -1388,6 +1388,113 @@ enum SpellCastTargetFlags
TARGET_FLAG_UNK2 = 0x00010000 // pguid TARGET_FLAG_UNK2 = 0x00010000 // pguid
}; };
enum ResponseCodes
{
RESPONSE_SUCCESS = 0x00,
RESPONSE_FAILURE = 0x01,
RESPONSE_CANCELLED = 0x02,
RESPONSE_DISCONNECTED = 0x03,
RESPONSE_FAILED_TO_CONNECT = 0x04,
RESPONSE_CONNECTED = 0x05,
RESPONSE_VERSION_MISMATCH = 0x06,
CSTATUS_CONNECTING = 0x07,
CSTATUS_NEGOTIATING_SECURITY = 0x08,
CSTATUS_NEGOTIATION_COMPLETE = 0x09,
CSTATUS_NEGOTIATION_FAILED = 0x0A,
CSTATUS_AUTHENTICATING = 0x0B,
AUTH_OK = 0x0C,
AUTH_FAILED = 0x0D,
AUTH_REJECT = 0x0E,
AUTH_BAD_SERVER_PROOF = 0x0F,
AUTH_UNAVAILABLE = 0x10,
AUTH_SYSTEM_ERROR = 0x11,
AUTH_BILLING_ERROR = 0x12,
AUTH_BILLING_EXPIRED = 0x13,
AUTH_VERSION_MISMATCH = 0x14,
AUTH_UNKNOWN_ACCOUNT = 0x15,
AUTH_INCORRECT_PASSWORD = 0x16,
AUTH_SESSION_EXPIRED = 0x17,
AUTH_SERVER_SHUTTING_DOWN = 0x18,
AUTH_ALREADY_LOGGING_IN = 0x19,
AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A,
AUTH_WAIT_QUEUE = 0x1B,
AUTH_BANNED = 0x1C,
AUTH_ALREADY_ONLINE = 0x1D,
AUTH_NO_TIME = 0x1E,
AUTH_DB_BUSY = 0x1F,
AUTH_SUSPENDED = 0x20,
AUTH_PARENTAL_CONTROL = 0x21,
AUTH_LOCKED_ENFORCED = 0x22,
REALM_LIST_IN_PROGRESS = 0x23,
REALM_LIST_SUCCESS = 0x24,
REALM_LIST_FAILED = 0x25,
REALM_LIST_INVALID = 0x26,
REALM_LIST_REALM_NOT_FOUND = 0x27,
ACCOUNT_CREATE_IN_PROGRESS = 0x28,
ACCOUNT_CREATE_SUCCESS = 0x29,
ACCOUNT_CREATE_FAILED = 0x2A,
CHAR_LIST_RETRIEVING = 0x2B,
CHAR_LIST_RETRIEVED = 0x2C,
CHAR_LIST_FAILED = 0x2D,
CHAR_CREATE_IN_PROGRESS = 0x2E,
CHAR_CREATE_SUCCESS = 0x2F,
CHAR_CREATE_ERROR = 0x30,
CHAR_CREATE_FAILED = 0x31,
CHAR_CREATE_NAME_IN_USE = 0x32,
CHAR_CREATE_DISABLED = 0x33,
CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34,
CHAR_CREATE_SERVER_LIMIT = 0x35,
CHAR_CREATE_ACCOUNT_LIMIT = 0x36,
CHAR_CREATE_SERVER_QUEUE = 0x37,
CHAR_CREATE_ONLY_EXISTING = 0x38,
CHAR_CREATE_EXPANSION = 0x39,
CHAR_CREATE_EXPANSION_CLASS = 0x3A,
CHAR_CREATE_LEVEL_REQUIREMENT = 0x3B,
CHAR_CREATE_UNIQUE_CLASS_LIMIT = 0x3C,
CHAR_DELETE_IN_PROGRESS = 0x3D,
CHAR_DELETE_SUCCESS = 0x3E,
CHAR_DELETE_FAILED = 0x3F,
CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x40,
CHAR_DELETE_FAILED_GUILD_LEADER = 0x41,
CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x42,
CHAR_LOGIN_IN_PROGRESS = 0x43,
CHAR_LOGIN_SUCCESS = 0x44,
CHAR_LOGIN_NO_WORLD = 0x45,
CHAR_LOGIN_DUPLICATE_CHARACTER = 0x46,
CHAR_LOGIN_NO_INSTANCES = 0x47,
CHAR_LOGIN_FAILED = 0x48,
CHAR_LOGIN_DISABLED = 0x49,
CHAR_LOGIN_NO_CHARACTER = 0x4A,
CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x4B,
CHAR_LOGIN_LOCKED_BY_BILLING = 0x4C,
CHAR_NAME_SUCCESS = 0x4D,
CHAR_NAME_FAILURE = 0x4E,
CHAR_NAME_NO_NAME = 0x4F,
CHAR_NAME_TOO_SHORT = 0x50,
CHAR_NAME_TOO_LONG = 0x51,
CHAR_NAME_INVALID_CHARACTER = 0x52,
CHAR_NAME_MIXED_LANGUAGES = 0x53,
CHAR_NAME_PROFANE = 0x54,
CHAR_NAME_RESERVED = 0x55,
CHAR_NAME_INVALID_APOSTROPHE = 0x56,
CHAR_NAME_MULTIPLE_APOSTROPHES = 0x57,
CHAR_NAME_THREE_CONSECUTIVE = 0x58,
CHAR_NAME_INVALID_SPACE = 0x59,
CHAR_NAME_CONSECUTIVE_SPACES = 0x5A,
CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x5B,
CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x5C,
CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5D
};
#define MAX_PLAYERNAME_LENGTH 12 #define MAX_PLAYERNAME_LENGTH 12
#define MIN_PLAYERNAME_LENGTH 2 #define MIN_PLAYERNAME_LENGTH 2

View File

@ -347,6 +347,7 @@ OpcodeHandler *WorldSession::_GetOpcodeHandlerTable() const
{SMSG_WHO, &WorldSession::_HandleWhoOpcode}, {SMSG_WHO, &WorldSession::_HandleWhoOpcode},
{SMSG_CREATURE_QUERY_RESPONSE, &WorldSession::_HandleCreatureQueryResponseOpcode}, {SMSG_CREATURE_QUERY_RESPONSE, &WorldSession::_HandleCreatureQueryResponseOpcode},
{SMSG_GAMEOBJECT_QUERY_RESPONSE, &WorldSession::_HandleGameobjectQueryResponseOpcode}, {SMSG_GAMEOBJECT_QUERY_RESPONSE, &WorldSession::_HandleGameobjectQueryResponseOpcode},
{SMSG_CHAR_CREATE, &WorldSession::_HandleCharCreateOpcode},
// table termination // table termination
{ 0, NULL } { 0, NULL }
@ -556,11 +557,11 @@ void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
recvPacket >> dummy32 >> dummy8 >> dummy32; recvPacket >> dummy32 >> dummy8 >> dummy32;
recvPacket >> expansion; recvPacket >> expansion;
if(errcode == 0xC) // TODO: add data to generic_text.scp and use the strings here
if(errcode == AUTH_OK)
{ {
logdetail("World Authentication successful, preparing for char list request..."); logdetail("World Authentication successful, preparing for char list request...");
WorldPacket pkt; WorldPacket pkt(CMSG_CHAR_ENUM, 0);
pkt.SetOpcode(CMSG_CHAR_ENUM);
SendWorldPacket(pkt); SendWorldPacket(pkt);
} }
else else
@ -591,7 +592,6 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
else else
{ {
logdetail("Chars in list: %u",num); logdetail("Chars in list: %u",num);
_LoadCache(); // we are about to login, so we need cache data
// TODO: load cache on loadingscreen // TODO: load cache on loadingscreen
for(unsigned int i=0;i<num;i++) for(unsigned int i=0;i<num;i++)
{ {
@ -622,7 +622,7 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
{ {
recvPacket >> plr[i]._items[inv].displayId >> plr[i]._items[inv].inventorytype >> dummy32; recvPacket >> plr[i]._items[inv].displayId >> plr[i]._items[inv].inventorytype >> dummy32;
} }
plrNameCache.AddInfo(plr[i]._guid, plr[i]._name); // TODO: set after loadingscreen, after loading cache plrNameCache.Add(plr[i]._guid, plr[i]._name); // TODO: set after loadingscreen, after loading cache
} }
char_found=false; char_found=false;
@ -747,6 +747,7 @@ void WorldSession::EnterWorldWithCharacter(std::string name)
void WorldSession::PreloadDataBeforeEnterWorld(PlayerEnum& pl) void WorldSession::PreloadDataBeforeEnterWorld(PlayerEnum& pl)
{ {
log("Loading data before entering world..."); log("Loading data before entering world...");
_LoadCache(); // we are about to login, so we need cache data
GetWorld()->GetMapMgr()->Update(pl._x, pl._y, pl._mapId); // make it load the map files GetWorld()->GetMapMgr()->Update(pl._x, pl._y, pl._mapId); // make it load the map files
// preload additional map data only when the GUI is enabled // preload additional map data only when the GUI is enabled
@ -1023,12 +1024,8 @@ void WorldSession::_HandleNameQueryResponseOpcode(WorldPacket& recvPacket)
if(pname.length()>MAX_PLAYERNAME_LENGTH || pname.length()<MIN_PLAYERNAME_LENGTH) if(pname.length()>MAX_PLAYERNAME_LENGTH || pname.length()<MIN_PLAYERNAME_LENGTH)
return; // playernames maxlen=12, minlen=2 return; // playernames maxlen=12, minlen=2
// rest of the packet is not interesting for now // rest of the packet is not interesting for now
if(plrNameCache.AddInfo(pguid,pname)) plrNameCache.Add(pguid,pname);
{
logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid); logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid);
//if(GetInstance()->GetConf()->debug > 1)
// SendChatMessage(CHAT_MSG_SAY,0,"Player "+pname+" added to cache.","");
}
WorldObject *wo = (WorldObject*)objmgr.GetObj(pguid); WorldObject *wo = (WorldObject*)objmgr.GetObj(pguid);
if(wo) if(wo)
wo->SetName(pname); wo->SetName(pname);
@ -1040,7 +1037,7 @@ void WorldSession::_HandlePongOpcode(WorldPacket& recvPacket)
recvPacket >> pong; recvPacket >> pong;
_lag_ms = clock() - pong; _lag_ms = clock() - pong;
if(GetInstance()->GetConf()->notifyping) if(GetInstance()->GetConf()->notifyping)
log("Recieved Ping reply: %u ms latency.", _lag_ms); log("Received Ping reply: %u ms latency.", _lag_ms);
} }
void WorldSession::_HandleTradeStatusOpcode(WorldPacket& recvPacket) void WorldSession::_HandleTradeStatusOpcode(WorldPacket& recvPacket)
{ {
@ -1049,6 +1046,7 @@ void WorldSession::_HandleTradeStatusOpcode(WorldPacket& recvPacket)
recvPacket >> unk; recvPacket >> unk;
if(unk==1) if(unk==1)
{ {
// TODO: Implement this!!
SendChatMessage(CHAT_MSG_SAY,0,"It has no sense trying to trade with me, that feature is not yet implemented!",""); SendChatMessage(CHAT_MSG_SAY,0,"It has no sense trying to trade with me, that feature is not yet implemented!","");
WorldPacket pkt; WorldPacket pkt;
pkt.SetOpcode(CMSG_CANCEL_TRADE); pkt.SetOpcode(CMSG_CANCEL_TRADE);
@ -1679,6 +1677,35 @@ void WorldSession::_HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket)
objmgr.AssignNameToObj(entry, TYPEID_GAMEOBJECT, go->name); objmgr.AssignNameToObj(entry, TYPEID_GAMEOBJECT, go->name);
} }
void WorldSession::_HandleCharCreateOpcode(WorldPacket& recvPacket)
{
uint8 response;
recvPacket >> response;
if(response == CHAR_CREATE_SUCCESS)
{
log("Character created successfully.");
WorldPacket pkt(CMSG_CHAR_ENUM, 0);
SendWorldPacket(pkt);
logdebug("Requested new CMSG_CHAR_ENUM");
}
else
{
logerror("Character creation error, response=%u", response);
}
if(SCPDatabase *db = GetInstance()->dbmgr.GetDB("generic_text"))
{
// convert response number to field name (simple int to string)
char buf[20];
sprintf(buf,"%u",response);
std::string response_str = db->GetString(0, buf); // data are expected to be at index 0
log("Response String: '%s'",response_str.c_str());
}
if(PseuGUI *gui = GetInstance()->GetGUI())
gui->SetSceneData(ISCENE_CHARSEL_ERRMSG, response);
}
// TODO: delete world on LogoutComplete once implemented // TODO: delete world on LogoutComplete once implemented

View File

@ -104,6 +104,7 @@ public:
void SendWhoListRequest(uint32 minlvl=0, uint32 maxlvl=100, uint32 racemask=-1, uint32 classmask=-1, std::string name="", std::string guildname="", std::vector<uint32> *zonelist=NULL, std::vector<std::string> *strlist=NULL); void SendWhoListRequest(uint32 minlvl=0, uint32 maxlvl=100, uint32 racemask=-1, uint32 classmask=-1, std::string name="", std::string guildname="", std::vector<uint32> *zonelist=NULL, std::vector<std::string> *strlist=NULL);
void SendQueryCreature(uint32 entry, uint64 guid = 0); void SendQueryCreature(uint32 entry, uint64 guid = 0);
void SendQueryGameobject(uint32 entry, uint64 guid = 0); void SendQueryGameobject(uint32 entry, uint64 guid = 0);
void SendCharCreate(std::string name, uint8 race, uint8 class_, uint8 gender=0, uint8 skin=0, uint8 face=0, uint8 hairstyle=0, uint8 haircolor=0, uint8 facial=0, uint8 outfit=0);
void HandleWorldPacket(WorldPacket*); void HandleWorldPacket(WorldPacket*);
@ -161,6 +162,7 @@ private:
void _HandleWhoOpcode(WorldPacket& recvPacket); void _HandleWhoOpcode(WorldPacket& recvPacket);
void _HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket); void _HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket);
void _HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket); void _HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket);
void _HandleCharCreateOpcode(WorldPacket& recvPacket);
// helper functions to keep SMSG_(COMPRESSED_)UPDATE_OBJECT easy to handle // helper functions to keep SMSG_(COMPRESSED_)UPDATE_OBJECT easy to handle
void _MovementUpdate(uint8 objtypeid, uint64 guid, WorldPacket& recvPacket); // Helper for _HandleUpdateObjectOpcode void _MovementUpdate(uint8 objtypeid, uint64 guid, WorldPacket& recvPacket); // Helper for _HandleUpdateObjectOpcode