* 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
1=Create New Character
[3]
0=Creating new Character...

View File

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

View File

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

View File

@ -39,7 +39,7 @@ class Scene
public:
Scene(PseuGUI *g);
~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 SceneState GetState(void) { return _scenestate; }
virtual void OnUpdate(s32);
@ -99,9 +99,12 @@ class SceneCharSelection : public Scene
public:
SceneCharSelection(PseuGUI *gui);
void OnUpdate(s32);
void OnManualUpdate(void);
void OnDelete(void);
void OnResize(void);
void FillCharlist(void);
private:
GUIEventReceiver *eventrecv;
IGUIWindow *realmwin;
@ -112,6 +115,8 @@ private:
IGUIComboBox *raceselect;
IGUIComboBox *classselect;
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
};

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);
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();
if(ws)
{
@ -75,29 +90,19 @@ SceneCharSelection::SceneCharSelection(PseuGUI *gui) : Scene(gui)
charlistbox->addItem(entry.c_str());
uint32 faction = racedb->GetInt(c.p._race, ffaction);
SColor col;
switch(faction)
{
case 1: col.set(0xFF, 0xFF, 0x30, 0x30); break;
case 7: col.set(0xFF, 0x30, 0x30, 0xFF); break;
default: col.set(0xFFFFFFFF);
case 1: col.set(0xFF, 0xFF, 0x30, 0x30); break;
case 7: col.set(0xFF, 0x30, 0x30, 0xFF); break;
default: col.set(0xFFFFFFFF);
}
charlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT,col);
charlistbox->setItemOverrideColor(i,EGUI_LBC_TEXT_HIGHLIGHT,col);
}
}
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)
@ -182,10 +187,11 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
{
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;
rect<s32> pos;
msgbox_textid = 0;
newcharwin = guienv->addWindow(CalcRelativeScreenPos(driver, 0.2f, 0.2f, 0.6f, 0.6f), true,
GetStringFromDB(ISCENE_CHARSEL_LABELS, DSCENE_CHARSEL_LABEL_NEWCHARWIN).c_str());
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);
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);
//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])
{
@ -299,21 +305,20 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
if(eventrecv->buttons & BUTTON_NEWCHARWIN_OK && newcharwin)
{
core::stringc tmp=charname->getText();
core::stringc chname = charname->getText();
u8 race = racemap[raceselect->getSelected()];
u8 cclass = classmap[classselect->getSelected()];
log("Creating character Race %i Class %i Name %s",race,cclass,tmp.c_str());
if(tmp.size() && race && cclass)
if(chname.size() && race && cclass)
{
WorldSession *ws=instance->GetWSession();
if(ws)
{
WorldPacket packet(CMSG_CHAR_CREATE,(tmp.size()+1)+1+1+1+1+1+1+1+1+1);
packet<<tmp.c_str();
// name, race, class, gender, skin, face, hairstyle, haircolor, facialhair, outfitID
packet << race << cclass <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0 <<(u8)0;
ws->AddSendWorldPacket(packet);
eventrecv->buttons |= BUTTON_NEWCHARWIN_CANCEL; // easiest way to close the window without much additional code
ws->SendCharCreate(chname.c_str(), race, cclass);
msgbox->setText(GetStringFromDB(3,0).c_str());
msgbox_textid = 0;
// do not close window until character created (will when getting response code 0)
}
else
logerror("Trying to create new Character, but no WorldSession exists.");
@ -323,18 +328,31 @@ void SceneCharSelection::OnUpdate(s32 timepassed)
}
// realmlist window
if(eventrecv->buttons & BUTTON_REALMWIN_CANCEL && realmwin)
{
realmwin->remove();
realmwin=NULL;
realmwin = NULL;
}
// new character window
if(eventrecv->buttons & BUTTON_NEWCHARWIN_CANCEL && newcharwin)
{
newcharwin->remove();
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;
@ -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_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_END
};
@ -72,6 +73,7 @@ enum SceneCharSelectLabels
DSCENE_CHARSEL_LABEL_NEWCHARWIN = 1,
};
#endif

View File

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

View File

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

View File

@ -40,7 +40,7 @@ void WorldSession::_HandleItemQuerySingleResponseOpcode(WorldPacket& recvPacket)
recvPacket >> proto->Stackable;
recvPacket >> proto->ContainerSlots;
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].ItemStatValue;

View File

@ -1388,6 +1388,113 @@ enum SpellCastTargetFlags
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 MIN_PLAYERNAME_LENGTH 2

View File

@ -347,6 +347,7 @@ OpcodeHandler *WorldSession::_GetOpcodeHandlerTable() const
{SMSG_WHO, &WorldSession::_HandleWhoOpcode},
{SMSG_CREATURE_QUERY_RESPONSE, &WorldSession::_HandleCreatureQueryResponseOpcode},
{SMSG_GAMEOBJECT_QUERY_RESPONSE, &WorldSession::_HandleGameobjectQueryResponseOpcode},
{SMSG_CHAR_CREATE, &WorldSession::_HandleCharCreateOpcode},
// table termination
{ 0, NULL }
@ -556,11 +557,11 @@ void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
recvPacket >> dummy32 >> dummy8 >> dummy32;
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...");
WorldPacket pkt;
pkt.SetOpcode(CMSG_CHAR_ENUM);
WorldPacket pkt(CMSG_CHAR_ENUM, 0);
SendWorldPacket(pkt);
}
else
@ -591,7 +592,6 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
else
{
logdetail("Chars in list: %u",num);
_LoadCache(); // we are about to login, so we need cache data
// TODO: load cache on loadingscreen
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;
}
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;
@ -747,6 +747,7 @@ void WorldSession::EnterWorldWithCharacter(std::string name)
void WorldSession::PreloadDataBeforeEnterWorld(PlayerEnum& pl)
{
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
// 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)
return; // playernames maxlen=12, minlen=2
// rest of the packet is not interesting for now
if(plrNameCache.AddInfo(pguid,pname))
{
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.","");
}
plrNameCache.Add(pguid,pname);
logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid);
WorldObject *wo = (WorldObject*)objmgr.GetObj(pguid);
if(wo)
wo->SetName(pname);
@ -1040,7 +1037,7 @@ void WorldSession::_HandlePongOpcode(WorldPacket& recvPacket)
recvPacket >> pong;
_lag_ms = clock() - pong;
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)
{
@ -1049,6 +1046,7 @@ void WorldSession::_HandleTradeStatusOpcode(WorldPacket& recvPacket)
recvPacket >> unk;
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!","");
WorldPacket pkt;
pkt.SetOpcode(CMSG_CANCEL_TRADE);
@ -1679,6 +1677,35 @@ void WorldSession::_HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket)
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

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 SendQueryCreature(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*);
@ -161,6 +162,7 @@ private:
void _HandleWhoOpcode(WorldPacket& recvPacket);
void _HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket);
void _HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket);
void _HandleCharCreateOpcode(WorldPacket& recvPacket);
// helper functions to keep SMSG_(COMPRESSED_)UPDATE_OBJECT easy to handle
void _MovementUpdate(uint8 objtypeid, uint64 guid, WorldPacket& recvPacket); // Helper for _HandleUpdateObjectOpcode