diff --git a/bin/_startup.def b/bin/_startup.def index fd0c06e..6638779 100644 --- a/bin/_startup.def +++ b/bin/_startup.def @@ -41,11 +41,5 @@ ELSE ENDIF UNSET errors -// Load some SCP files -LOADALLSCP - -// do more stuff here in future... - -LOG * StartUp complete! - +LOG *** StartUp complete! diff --git a/bin/data/scp/class.scp b/bin/data/scp/class.scp index d5cc748..2f57bc1 100644 --- a/bin/data/scp/class.scp +++ b/bin/data/scp/class.scp @@ -1,3 +1,5 @@ +#dbname=class + [1] name=Warrior diff --git a/bin/data/scp/gender.scp b/bin/data/scp/gender.scp index cc91951..78fc160 100644 --- a/bin/data/scp/gender.scp +++ b/bin/data/scp/gender.scp @@ -1,4 +1,4 @@ -// define names of genders +#dbname=gender [0] name=male diff --git a/bin/data/scp/gui_login_text.scp b/bin/data/scp/gui_login_text.scp new file mode 100644 index 0000000..46a1663 --- /dev/null +++ b/bin/data/scp/gui_login_text.scp @@ -0,0 +1,25 @@ +#dbname=gui_login_text + +// check src/Client/GUI/SceneData.h for the fields/numbers. +// this file covers the texts for SceneLogin. + +// connection info +[1] +0=Not connected. +1=Connecting... +2=Could not connect. +3=Account does not exist! +4=Account is already connected! +5=Wrong game version. (Try to set a different version info in PseuWoW.conf) +6=Logging in... +7=Authenticating... +8=Authentication failed! (Wrong password?) +9=Requesting realmlist... +10=Unknown error! +11=Incoming file transfer. + +// msgbox texts. 0: header 1:body +[2] +0=Oh noes! +1=You have to enter account name and password! + diff --git a/bin/data/scp/language.scp b/bin/data/scp/language.scp index 17cf722..8b5d831 100644 --- a/bin/data/scp/language.scp +++ b/bin/data/scp/language.scp @@ -1,3 +1,5 @@ +#dbname=language + [0] name=Global diff --git a/bin/scripts/__core_func.def b/bin/scripts/__core_func.def index 485ec39..1f55ef2 100644 --- a/bin/scripts/__core_func.def +++ b/bin/scripts/__core_func.def @@ -21,45 +21,6 @@ SET,${v} ${${v}}${@def} // remove the name placeholder UNSET v - -//-------------------------------------------------------- -#script=exloadscp -#permission=255 -//-------------------------------------------------------- -if ?{fileexists ${@def}} - loadscp,{${@0}} ${@def} -else - logdebug skipped loading of non-existent file '${@def}' -endif - - -//-------------------------------------------------------- -#script=loadallscp -#permission=255 -//-------------------------------------------------------- -LOG * Loading SCP data storages... - -// example: -// LOADSCP,test data/test.scp - -// load default databases -LOADSCP,class data/scp/class.scp -LOADSCP,gender data/scp/gender.scp -LOADSCP,language data/scp/language.scp -LOADSCP,map data/scp/map.scp -LOADSCP,race data/scp/race.scp - -// load extended databases if present. -EXLOADSCP,sound data/scp/sound.scp -EXLOADSCP,emote data/scp/emote.scp -EXLOADSCP,zone data/scp/zone.scp -EXLOADSCP,creaturedisplayinfo data/scp/creaturedisplayinfo.scp -EXLOADSCP,creaturemodeldata data/scp/creaturemodeldata.scp -EXLOADSCP,npcsound data/scp/npcsound.scp - -LOG * SCP loaded. - - //------------------------------------------------- #script=string_is_command //------------------------------------------------- diff --git a/bin/scripts/database_loader.def b/bin/scripts/database_loader.def new file mode 100644 index 0000000..f4cd546 --- /dev/null +++ b/bin/scripts/database_loader.def @@ -0,0 +1,45 @@ +#script=register_db_loader +if ?{not ?{IsHooked _startup}} + HookStart _startup + HookAdd db_loader_load_all + HookEnd + + // set up paths; ./data/scp and ./cache are set in the core already + // the SCP files placed in this directory are used to override some values + // in already present SCP files or to add custom fields or content + // note: it DOES matter in which order paths are added!! + AddDBPath ./data/scp-patches +endif + +//--------------------------------------------------------- +#script=db_loader_load_all + +log ** Loading / dyncompiling databases... + +// game databases +LoadDB race +LoadDB class +LoadDB gender +LoadDB language +LoadDB emote +LoadDB map +LoadDB zone +LoadDB creaturedisplayinfo +LoadDB creaturemodeldata +// LoadDB itemdisplayinfo // not yet used +// LoadDB charsections // not yet used +// LoadDB sound // not yet used +// LoadDB npcsound // not yet used + +// GUI related databases +LoadDB gui_login_text + + +log ** Databases loaded. + + +//---------------------------------------------------------- +#script=dummy +#onload +register_db_loader +#/onload diff --git a/src/Client/DefScript/DefScript.h b/src/Client/DefScript/DefScript.h index 14d8ca0..471e6ba 100644 --- a/src/Client/DefScript/DefScript.h +++ b/src/Client/DefScript/DefScript.h @@ -29,6 +29,7 @@ struct DefReturnResult DefReturnResult(bool b) { ok=true; mustreturn=false; ret=b?"true":"false"; } DefReturnResult(std::string s) { ok=true; mustreturn=false; ret=s; } DefReturnResult(const char *s) { DefReturnResult(std::string(s)); } + DefReturnResult(char *s) { DefReturnResult(std::string(s)); } bool ok; // true if the execution of the current statement was successful bool mustreturn; std::string ret; // return value used by ?{..} diff --git a/src/Client/DefScriptInterface.cpp b/src/Client/DefScriptInterface.cpp index 50bafda..92a8cf0 100644 --- a/src/Client/DefScriptInterface.cpp +++ b/src/Client/DefScriptInterface.cpp @@ -32,10 +32,6 @@ void DefScriptPackage::_InitDefScriptInterface(void) AddFunc("castspell",&DefScriptPackage::SCcastspell); AddFunc("queryitem",&DefScriptPackage::SCqueryitem); AddFunc("target",&DefScriptPackage::SCtarget); - AddFunc("loadscp",&DefScriptPackage::SCloadscp); - AddFunc("scpexists",&DefScriptPackage::SCScpExists); - AddFunc("scpsectionexists",&DefScriptPackage::SCScpSectionExists); - AddFunc("scpentryexists",&DefScriptPackage::SCScpEntryExists); AddFunc("getscpvalue",&DefScriptPackage::SCGetScpValue); AddFunc("getplayerguid",&DefScriptPackage::SCGetPlayerGuid); AddFunc("getname",&DefScriptPackage::SCGetName); @@ -61,6 +57,8 @@ void DefScriptPackage::_InitDefScriptInterface(void) AddFunc("switchopcodehandler",&DefScriptPackage::SCSwitchOpcodeHandler); AddFunc("opcodedisabled",&DefScriptPackage::SCOpcodeDisabled); AddFunc("spoofworldpacket",&DefScriptPackage::SCSpoofWorldPacket); + AddFunc("loaddb",&DefScriptPackage::SCLoadDB); + AddFunc("adddbpath",&DefScriptPackage::SCAddDBPath); } DefReturnResult DefScriptPackage::SCshdn(CmdSet& Set) @@ -81,15 +79,17 @@ DefReturnResult DefScriptPackage::SCSendChatMessage(CmdSet& Set){ DEF_RETURN_ERROR; } std::stringstream ss; + SCPDatabaseMgr& dbmgr = ((PseuInstance*)parentMethod)->dbmgr; uint32 type=atoi(Set.arg[0].c_str()); uint32 lang=atoi(Set.arg[1].c_str()); ss << lang; if(ss.str()!=Set.arg[1]) // given lang is NOT a number { - uint32 dblang; - dblang = ((PseuInstance*)parentMethod)->dbmgr.GetDB("language").GetFieldByValue("name",Set.arg[1]); + SCPDatabase *langdb = dbmgr.GetDB("language"); + uint32 dblang = langdb->GetFieldByStringValue("name",(char*)Set.arg[1].c_str()); logdev("looking up language id for lang '%s', found %i",Set.arg[1].c_str(),dblang); + // TODO: comment this out to enable using addon language??! if(dblang != -1) lang = dblang; } @@ -135,12 +135,13 @@ DefReturnResult DefScriptPackage::SCemote(CmdSet& Set){ // this supports calls like "emote 126" and "emote ready" uint32 id = uint32(-1); SCPDatabaseMgr& dbmgr = ((PseuInstance*)parentMethod)->dbmgr; - if(dbmgr.HasDB("emote")) + SCPDatabase *emotedb = dbmgr.GetDB("emote"); + if(emotedb) { - SCPDatabase& db = dbmgr.GetDB("emote"); - id = db.GetFieldByValue("name",DefScriptTools::stringToUpper(Set.defaultarg)); // emote names are always uppercased + + id = emotedb->GetFieldByStringValue("name",(char*)DefScriptTools::stringToUpper(Set.defaultarg).c_str()); // emote names are always uppercased } - if(id == uint32(-1)) + if(id == SCP_INVALID_INT) { id=atoi(Set.defaultarg.c_str()); if(!id) @@ -339,6 +340,7 @@ DefReturnResult DefScriptPackage::SCtarget(CmdSet& Set) return ""; } +/* DefReturnResult DefScriptPackage::SCloadscp(CmdSet& Set) { SCPDatabaseMgr& dbmgr = ((PseuInstance*)parentMethod)->dbmgr; @@ -366,38 +368,9 @@ DefReturnResult DefScriptPackage::SCloadscp(CmdSet& Set) logerror("Failed to load SCP: \"%s\" [%s]",dbname.c_str(),Set.defaultarg.c_str()); } } - return DefScriptTools::toString((uint64)sections);; + return DefScriptTools::toString((uint64)sections); } - -DefReturnResult DefScriptPackage::SCScpExists(CmdSet& Set) -{ - return (!Set.defaultarg.empty()) && ((PseuInstance*)parentMethod)->dbmgr.HasDB(Set.defaultarg); -} - -DefReturnResult DefScriptPackage::SCScpSectionExists(CmdSet& Set) -{ - static std::string dbname; - if(!Set.arg[0].empty()) - dbname=Set.arg[0]; - return (!Set.defaultarg.empty()) && (!dbname.empty()) - && ((PseuInstance*)parentMethod)->dbmgr.HasDB(dbname) - && ((PseuInstance*)parentMethod)->dbmgr.GetDB(dbname).HasField((uint32)DefScriptTools::toUint64(Set.defaultarg)); -} - -DefReturnResult DefScriptPackage::SCScpEntryExists(CmdSet& Set) -{ - static std::string dbname; - static uint32 keyid; - if(!Set.arg[0].empty()) - dbname=Set.arg[0]; - if(!Set.arg[1].empty()) - keyid=(uint32)DefScriptTools::toUint64(Set.arg[1]); - return (!Set.defaultarg.empty()) && (!dbname.empty()) - && ((PseuInstance*)parentMethod)->dbmgr.HasDB(dbname) - && ((PseuInstance*)parentMethod)->dbmgr.GetDB(dbname).HasField(keyid) - && ((PseuInstance*)parentMethod)->dbmgr.GetDB(dbname).GetField(keyid).HasEntry(Set.defaultarg); -} - +*/ // GetScpValue,db,key entry // db & key will be stored, that multiple calls like GetScpValue entryxyz are possible @@ -406,7 +379,7 @@ DefReturnResult DefScriptPackage::SCGetScpValue(CmdSet& Set) static std::string dbname; static uint32 keyid; std::string entry; - DefReturnResult r; + SCPDatabaseMgr& dbmgr = ((PseuInstance*)parentMethod)->dbmgr; if(!Set.arg[0].empty()) dbname=Set.arg[0]; @@ -414,18 +387,36 @@ DefReturnResult DefScriptPackage::SCGetScpValue(CmdSet& Set) keyid=(uint32)DefScriptTools::toUint64(Set.arg[1]); if(!Set.defaultarg.empty()) entry=Set.defaultarg; - if( (!entry.empty()) && (!dbname.empty()) - && ((PseuInstance*)parentMethod)->dbmgr.HasDB(dbname) - && ((PseuInstance*)parentMethod)->dbmgr.GetDB(dbname).HasField(keyid) - && ((PseuInstance*)parentMethod)->dbmgr.GetDB(dbname).GetField(keyid).HasEntry(entry)) + if( (!entry.empty()) && (!dbname.empty()) ) { - r.ret = ((PseuInstance*)parentMethod)->dbmgr.GetDB(dbname).GetField(keyid).GetString(entry); + SCPDatabase *db = dbmgr.GetDB(dbname); + if(db) + { + uint32 ftype = db->GetFieldType((char*)entry.c_str()); + switch(ftype) + { + case SCP_TYPE_INT: + { + return DefScriptTools::toString(db->GetInt(keyid,(char*)entry.c_str())); + } + case SCP_TYPE_FLOAT: + { + return DefScriptTools::toString(db->GetFloat(keyid,(char*)entry.c_str())); + } + case SCP_TYPE_STRING: + { + return std::string(db->GetString(keyid,(char*)entry.c_str())); + } + default: logerror("GetSCPValue: field '%s' does not exist in DB '%s'!",entry.c_str(),dbname.c_str()); + } + } + else + { + logerror("GetSCPValue: No such DB: '%s'",dbname.c_str()); + } } - else - { - r.ret = ""; - } - return r; + + return ""; } DefReturnResult DefScriptPackage::SCGetPlayerGuid(CmdSet& Set) @@ -825,15 +816,16 @@ DefReturnResult DefScriptPackage::SCGetFileList(CmdSet& Set) DefReturnResult DefScriptPackage::SCPrintScript(CmdSet &Set) { DefScript *sc = GetScript(DefScriptTools::stringToLower(Set.defaultarg)); - if(sc) + if(!sc) + return false; + + logcustom(0,GREEN,"== DefScript \"%s\", %u lines: ==",sc->GetName().c_str(),sc->GetLines()); + for(uint32 i = 0; i < sc->GetLines(); i++) { - logcustom(0,GREEN,"== DefScript \"%s\", %u lines: ==",sc->GetName().c_str(),sc->GetLines()); - for(uint32 i = 0; i < sc->GetLines(); i++) - { - logcustom(0,GREEN,sc->GetLine(i).c_str()); - } + logcustom(0,GREEN,sc->GetLine(i).c_str()); } - return ""; + + return true; } DefReturnResult DefScriptPackage::SCGetObjectValue(CmdSet &Set) @@ -1100,7 +1092,7 @@ DefReturnResult DefScriptPackage::SCSwitchOpcodeHandler(CmdSet &Set) WorldSession *ws = ((PseuInstance*)parentMethod)->GetWSession(); if(!ws) { - logerror("Invalid Script call: SCRemoveOpcodeHandler: WorldSession not valid"); + logerror("Invalid Script call: SCSwitchOpcodeHandler: WorldSession not valid"); DEF_RETURN_ERROR; } uint16 opc = (uint16)DefScriptTools::toUint64(Set.arg[0]); @@ -1173,6 +1165,23 @@ DefReturnResult DefScriptPackage::SCSpoofWorldPacket(CmdSet &Set) return false; } +DefReturnResult DefScriptPackage::SCLoadDB(CmdSet &Set) +{ + PseuInstance *ins = (PseuInstance*)parentMethod; + if(ins->dbmgr.GetDB(Set.defaultarg.c_str())) + return "exists"; + logdetail("Loading database '%s'",Set.defaultarg.c_str()); + uint32 result = ins->dbmgr.SearchAndLoad((char*)Set.defaultarg.c_str(), false); + return toString(result); +} + +DefReturnResult DefScriptPackage::SCAddDBPath(CmdSet &Set) +{ + PseuInstance *ins = (PseuInstance*)parentMethod; + ins->dbmgr.AddSearchPath((char*)Set.defaultarg.c_str()); + return true; +} + void DefScriptPackage::My_LoadUserPermissions(VarSet &vs) { static char *prefix = "USERS::"; diff --git a/src/Client/DefScriptInterfaceInclude.h b/src/Client/DefScriptInterfaceInclude.h index 2d65db1..fe501fb 100644 --- a/src/Client/DefScriptInterfaceInclude.h +++ b/src/Client/DefScriptInterfaceInclude.h @@ -23,10 +23,6 @@ DefReturnResult SClogerror(CmdSet&); DefReturnResult SCcastspell(CmdSet&); DefReturnResult SCqueryitem(CmdSet&); DefReturnResult SCtarget(CmdSet&); -DefReturnResult SCloadscp(CmdSet&); -DefReturnResult SCScpExists(CmdSet&); -DefReturnResult SCScpSectionExists(CmdSet&); -DefReturnResult SCScpEntryExists(CmdSet&); DefReturnResult SCGetScpValue(CmdSet&); DefReturnResult SCGetName(CmdSet&); DefReturnResult SCGetPlayerGuid(CmdSet&); @@ -52,6 +48,8 @@ DefReturnResult SCGetObjectDistance(CmdSet&); DefReturnResult SCSwitchOpcodeHandler(CmdSet&); DefReturnResult SCOpcodeDisabled(CmdSet&); DefReturnResult SCSpoofWorldPacket(CmdSet&); +DefReturnResult SCLoadDB(CmdSet &Set); +DefReturnResult SCAddDBPath(CmdSet &Set); void my_print(const char *fmt, ...); diff --git a/src/Client/GUI/DrawObject.cpp b/src/Client/GUI/DrawObject.cpp index b46521b..974851b 100644 --- a/src/Client/GUI/DrawObject.cpp +++ b/src/Client/GUI/DrawObject.cpp @@ -47,11 +47,11 @@ void DrawObject::_Init(void) if(!cube && _obj->IsWorldObject()) // only world objects have coords and can be drawn { uint32 displayid = _obj->IsUnit() ? _obj->GetUInt32Value(UNIT_FIELD_DISPLAYID) : 0; // TODO: in case its GO get it from proto data - SCPDatabase& cdi = _instance->dbmgr.GetDB("creaturedisplayinfo"); - SCPField& crdata = cdi.GetField(displayid); - uint32 modelid = crdata.GetInteger("model"); - std::string modelfile = std::string("data/model/") + _instance->dbmgr.GetDB("creaturemodeldata").GetField(modelid).GetString("file"); - uint32 opacity = crdata.GetInteger("opacity"); + SCPDatabase *cdi = _instance->dbmgr.GetDB("creaturedisplayinfo"); + SCPDatabase *cmd = _instance->dbmgr.GetDB("creaturemodeldata"); + uint32 modelid = cdi && displayid ? cdi->GetUint32(displayid,"model") : 0; + std::string modelfile = std::string("data/model/") + cmd->GetString(modelid,"file"); + uint32 opacity = cdi && displayid ? cdi->GetUint32(displayid,"opacity") : 255; scene::IAnimatedMesh *mesh = _smgr->getMesh(modelfile.c_str()); if(mesh) { diff --git a/src/Client/GUI/PseuGUI.h b/src/Client/GUI/PseuGUI.h index e7f7243..55806cc 100644 --- a/src/Client/GUI/PseuGUI.h +++ b/src/Client/GUI/PseuGUI.h @@ -2,6 +2,7 @@ #define PSEUGUI_H #include "irrlicht/irrlicht.h" +#include "SceneData.h" #include "DrawObjMgr.h" #include "World.h" diff --git a/src/Client/GUI/Scene.cpp b/src/Client/GUI/Scene.cpp index c3336e6..448abce 100644 --- a/src/Client/GUI/Scene.cpp +++ b/src/Client/GUI/Scene.cpp @@ -7,6 +7,7 @@ Scene::Scene(PseuGUI *g) { memset(scenedata, 0, sizeof(uint32) * SCENEDATA_SIZE); + textdb = NULL; gui = g; instance = gui->GetInstance(); device = gui->_device; @@ -45,3 +46,22 @@ Scene::~Scene() { DEBUG(logdebug("Scene::~Scene()")); } + +core::stringw Scene::GetStringFromDB(u32 index, u32 entry) +{ + core::stringw r = ""; + if(!textdb) + { + r += L""; + return r; + } + char buf[20]; + sprintf(buf,"%u",entry); + r += textdb->GetString(index, buf); + textdb->DumpStructureToFile("DB_textdb.txt"); + return r; +} diff --git a/src/Client/GUI/Scene.h b/src/Client/GUI/Scene.h index 62b4604..73a0cf6 100644 --- a/src/Client/GUI/Scene.h +++ b/src/Client/GUI/Scene.h @@ -10,7 +10,7 @@ using namespace scene; using namespace video; using namespace io; using namespace gui; - + class PseuGUI; class CCursorController; @@ -22,6 +22,7 @@ class Scene public: Scene(PseuGUI *g); ~Scene(); + core::stringw GetStringFromDB(u32 index, u32 entry); inline void SetState(SceneState sc) { _scenestate = sc; } inline SceneState GetState(void) { return _scenestate; } virtual void OnUpdate(s32); @@ -40,6 +41,7 @@ protected: CCursorController *cursor; SceneState _scenestate; uint32 scenedata[SCENEDATA_SIZE]; // generic storage for anything the PseuInstance thread wants to tell us + SCPDatabase *textdb; }; class SceneGuiStart : public Scene @@ -51,22 +53,24 @@ private: IGUIImage *irrlogo, *driverlogo; }; - -class GUIEventReceiver; -class SceneLogin : public Scene -{ -public: - SceneLogin(PseuGUI *gui); - void OnUpdate(s32); - void OnDelete(void); - -private: - gui::IGUIElement* root; - IGUIImage *irrlogo, *background; - GUIEventReceiver *eventrecv; - PseuGUI* _gui; -}; +class GUIEventReceiver; + +class SceneLogin : public Scene +{ +public: + SceneLogin(PseuGUI *gui); + void OnUpdate(s32); + void OnDelete(void); + +private: + gui::IGUIElement* root; + IGUIImage *irrlogo, *background; + GUIEventReceiver *eventrecv; + PseuGUI* _gui; + gui::IGUIElement *msgbox; + uint32 msgbox_textid; +}; class ShTlTerrainSceneNode; class MCameraFPS; @@ -119,4 +123,4 @@ private: -#endif +#endif diff --git a/src/Client/GUI/SceneData.h b/src/Client/GUI/SceneData.h index 6af1395..40e904d 100644 --- a/src/Client/GUI/SceneData.h +++ b/src/Client/GUI/SceneData.h @@ -3,24 +3,31 @@ #define SCENEDATA_SIZE 255 -// I: index +// I: index, enums should start with 1 // D: data value +// dummy indexes are used to keep space for misc text data in an SCP file enum SceneLoginDataIndexes { - ISCENE_LOGIN_CONN_STATUS, - ISCENE_LOGIN_END + ISCENE_LOGIN_CONN_STATUS = 1, + ISCENE_LOGIN_MSGBOX_DUMMY = 2, + ISCENE_LOGIN_END = 3 }; enum SceneLoginConnStatus { - DSCENE_LOGIN_NOT_CONNECTED, - DSCENE_LOGIN_CONN_ATTEMPT, - DSCENE_LOGIN_CONN_FAILED, - DSCENE_LOGIN_LOGGING_IN, - DSCENE_LOGIN_AUTHENTICATING, - DSCENE_LOGIN_AUTH_FAILED, - DSCENE_LOGIN_AUTH_OK + DSCENE_LOGIN_NOT_CONNECTED = 0, + DSCENE_LOGIN_CONN_ATTEMPT = 1, + DSCENE_LOGIN_CONN_FAILED = 2, + DSCENE_LOGIN_ACC_NOT_FOUND = 3, + DSCENE_LOGIN_ALREADY_CONNECTED = 4, + DSCENE_LOGIN_WRONG_VERSION = 5, + DSCENE_LOGIN_LOGGING_IN = 6, + DSCENE_LOGIN_AUTHENTICATING = 7, + DSCENE_LOGIN_AUTH_FAILED = 8, + DSCENE_LOGIN_REQ_REALM = 9, + DSCENE_LOGIN_UNK_ERROR = 10, + DSCENE_LOGIN_FILE_TRANSFER = 11, }; diff --git a/src/Client/GUI/SceneLogin.cpp b/src/Client/GUI/SceneLogin.cpp index 7b2a4b3..7254b8b 100644 --- a/src/Client/GUI/SceneLogin.cpp +++ b/src/Client/GUI/SceneLogin.cpp @@ -48,7 +48,8 @@ public: SceneLogin::SceneLogin(PseuGUI *gui) : Scene(gui) { - _gui=gui; + textdb = instance->dbmgr.GetDB("gui_login_text"); + msgbox_textid = 0; eventrecv = new GUIEventReceiver(); device->setEventReceiver(eventrecv); root = guienv->getRootGUIElement(); @@ -67,17 +68,21 @@ SceneLogin::SceneLogin(PseuGUI *gui) : Scene(gui) guienv->addButton(rect(scrn.Width-120, scrn.Height-40, scrn.Width-10, scrn.Height-10), 0, 4, L"Quit"); guienv->addButton(rect(10, scrn.Height-40, 120, scrn.Height-10), 0, 8, L"Community Site"); guienv->addButton(rect((scrn.Width*0.5f)-60, (scrn.Height*0.3f)+100, (scrn.Width*0.5f)+60, (scrn.Height*0.3f)+130), 0, 16, L"Logon"); - + msgbox = guienv->addStaticText(GetStringFromDB(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_NOT_CONNECTED).c_str(),rect((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+150, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+180),true,true); } void SceneLogin::OnUpdate(s32 timepassed) { + if(msgbox_textid != scenedata[ISCENE_LOGIN_CONN_STATUS]) + { + msgbox_textid = scenedata[ISCENE_LOGIN_CONN_STATUS]; + msgbox->setText(GetStringFromDB(ISCENE_LOGIN_CONN_STATUS,msgbox_textid).c_str()); + } + if(eventrecv->buttons & BUTTON_QUIT) { - _gui->Shutdown(); - _gui->GetInstance()->Stop(); - eventrecv->buttons=0; + instance->Stop(); } if(eventrecv->buttons & BUTTON_LOGON) { @@ -90,18 +95,21 @@ void SceneLogin::OnUpdate(s32 timepassed) std::string accpass=tmp.c_str(); if(accname.size() && accpass.size()) { + SetData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_CONN_ATTEMPT); logdebug("Trying to set Logon Data %u, %u", accname.size(), accpass.size()); // we can safely override the conf settings - _gui->GetInstance()->GetConf()->accname = accname; - _gui->GetInstance()->GetConf()->accpass = accpass; - _gui->GetInstance()->CreateRealmSession(); + instance->GetConf()->accname = accname; + instance->GetConf()->accpass = accpass; + instance->CreateRealmSession(); } else { - guienv->addMessageBox(L"Oh noes!", L"You have to enter account name and password!"); + guienv->addMessageBox(GetStringFromDB(ISCENE_LOGIN_MSGBOX_DUMMY,0).c_str(), + GetStringFromDB(ISCENE_LOGIN_MSGBOX_DUMMY,1).c_str()); } } + eventrecv->buttons = 0; } void SceneLogin::OnDelete(void) diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp index 393a7e4..cb7c6f3 100644 --- a/src/Client/PseuWoW.cpp +++ b/src/Client/PseuWoW.cpp @@ -117,6 +117,9 @@ bool PseuInstance::Init(void) _scp->SetPath(_scpdir); + dbmgr.AddSearchPath("./cache"); + dbmgr.AddSearchPath("./data/scp"); + _scp->variables.Set("@version_short",_ver_short); _scp->variables.Set("@version",_ver); _scp->variables.Set("@inworld","false"); @@ -412,9 +415,9 @@ bool PseuInstance::ConnectToRealm(void) _rsession = new RealmSession(this); _rsession->SetLogonData(); // get accname & accpass from PseuInstanceConfig and set it in the realm session _rsession->Connect(); - if(_rsession->MustDie()) // something failed. it will be deleted in next Update() call + if(_rsession->MustDie() || !_rsession->SocketGood()) // something failed. it will be deleted in next Update() call { - logerror("Connecting to Realm failed!"); + logerror("PseuInstance: Connecting to Realm failed!"); if(_gui) _gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_CONN_FAILED); return false; diff --git a/src/Client/Realm/RealmSession.cpp b/src/Client/Realm/RealmSession.cpp index a8b0c79..657724e 100644 --- a/src/Client/Realm/RealmSession.cpp +++ b/src/Client/Realm/RealmSession.cpp @@ -315,6 +315,8 @@ void RealmSession::SendLogonChallenge(void) GetInstance()->SetError(); return; } + if(PseuGUI *gui = GetInstance()->GetGUI()) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_LOGGING_IN); std::string acc = stringToUpper(_accname); ByteBuffer packet; packet << (uint8)AUTH_LOGON_CHALLENGE; @@ -338,11 +340,14 @@ void RealmSession::SendLogonChallenge(void) void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt) { + PseuGUI *gui = GetInstance()->GetGUI(); logdebug("RealmSocket: Got AUTH_LOGON_CHALLENGE [%u of %u bytes]",pkt.size(),sizeof(sAuthLogonChallenge_S)); if(pkt.size() < 3) { logerror("AUTH_LOGON_CHALLENGE: Recieved incorrect/unknown packet. Hexdump:"); DumpInvalidPacket(pkt); + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_UNK_ERROR); return; } @@ -353,18 +358,25 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt) { case 4: logerror("Realm Server did not find account \"%s\"!",_accname.c_str()); + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_ACC_NOT_FOUND); break; case 6: logerror("Account \"%s\" is already logged in!",_accname.c_str()); - // TODO: wait a certain amount of time before reconnecting? conf option? + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_ALREADY_CONNECTED); break; case 9: logerror("Realm Server doesn't accept this version!"); + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_WRONG_VERSION); break; case 0: { pkt.read((uint8*)&lc, sizeof(sAuthLogonChallenge_S)); logdetail("Login successful, now calculating proof packet..."); + if(PseuGUI *gui = GetInstance()->GetGUI()) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_AUTHENTICATING); // now lets start calculating BigNumber N,A,B,a,u,x,v,S,salt,unk1,g,k(3); // init BNs, default k to 3 @@ -501,12 +513,15 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt) void RealmSession::_HandleLogonProof(ByteBuffer& pkt) { + PseuGUI *gui = GetInstance()->GetGUI(); logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]",pkt.size(),26); if(pkt.size() < 2) { logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:"); DumpInvalidPacket(pkt); DieOrReconnect(true); + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_UNK_ERROR); return; } uint8 error = pkt[1]; @@ -516,11 +531,15 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt) { case REALM_AUTH_UPDATE_CLIENT: log("The realm server requested client update."); + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_WRONG_VERSION); DieOrReconnect(true); return; case REALM_AUTH_NO_MATCH: case REALM_AUTH_UNKNOWN2: + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_AUTH_FAILED); logerror("Wrong password or invalid account information or authentication error"); DieOrReconnect(true); return; @@ -530,6 +549,8 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt) if(error != REALM_AUTH_SUCCESS) { logerror("AUTH_LOGON_PROOF: unk error = 0x%X",error); + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_UNK_ERROR); pkt.rpos(2); DieOrReconnect(true); return; @@ -542,6 +563,8 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt) //printchex((char*)&lp, sizeof(sAuthLogonProof_S),true); if(!memcmp(lp.M2,this->_m2,20)) { + if(PseuGUI *gui = GetInstance()->GetGUI()) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS, DSCENE_LOGIN_REQ_REALM); // auth successful ByteBuffer packet; packet << (uint8)REALM_LIST; @@ -553,7 +576,8 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt) logcritical("Auth failed, M2 differs!"); printf("My M2 :"); printchex((char*)_m2,20,true); printf("Srv M2:"); printchex((char*)lp.M2,20,true); - + if(gui) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_AUTH_FAILED); DieOrReconnect(true); } } @@ -576,6 +600,8 @@ void RealmSession::_HandleTransferInit(ByteBuffer& pkt) pkt >> _file_size; pkt.read(_file_md5,MD5_DIGEST_LENGTH); logcustom(0,GREEN,"TransferInit [%s]: File size: "I64FMTD" KB (MD5: %s)", (char*)type_str, _file_size / 1024L, toHexDump(&_file_md5[0],MD5_DIGEST_LENGTH,false).c_str()); + if(PseuGUI *gui = GetInstance()->GetGUI()) + gui->SetSceneData(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_FILE_TRANSFER); delete [] type_str; ByteBuffer bb(1); bb << uint8(XFER_ACCEPT); @@ -708,3 +734,8 @@ void RealmSession::DieOrReconnect(bool err) GetInstance()->SetError(); } } + +bool RealmSession::SocketGood(void) +{ + return _socket && _socket->IsOk(); +} diff --git a/src/Client/Realm/RealmSession.h b/src/Client/Realm/RealmSession.h index 10639e8..815ec8e 100644 --- a/src/Client/Realm/RealmSession.h +++ b/src/Client/Realm/RealmSession.h @@ -21,7 +21,7 @@ public: void SendLogonChallenge(void); bool MustDie(void); void SetMustDie(void); - + bool SocketGood(void); private: diff --git a/src/Client/SCPDatabase.cpp b/src/Client/SCPDatabase.cpp index 8b37759..34d86b6 100644 --- a/src/Client/SCPDatabase.cpp +++ b/src/Client/SCPDatabase.cpp @@ -1,210 +1,839 @@ #include #include "common.h" +#include "Auth/MD5Hash.h" #include "SCPDatabase.h" +#define HEADER_SIZE (21*sizeof(uint32)) -uint32 SCPDatabase::LoadFromFile(char *fn) +inline char *gettypename(uint32 ty) { - std::fstream fh; - uint32 size = GetFileSize(fn); - if(!size) - return 0; - - fh.open(fn,std::ios_base::in | std::ios_base::binary); - if( !fh.is_open() ) - return 0; - - char *buf = new char[size]; - fh.read(buf,size); - fh.close(); - - uint32 sections = LoadFromMem(buf,size); - delete [] buf; - return sections; + return (ty==0 ? "INT" : (ty==1 ? "FLOAT" : "STRING")); } - -uint32 SCPDatabase::LoadFromMem(char *buf, uint32 size) +// file-globally declared pointer holder. NOT multi-instance-safe for now!! +struct memblock { - std::string line,value,entry,storage; - uint32 id=0,sections=0; + memblock() : ptr(NULL), size(0) {} + memblock(uint8 *p, uint32 s) : size(s), ptr(p) {} + ~memblock() { if(ptr) delete [] ptr; } + uint8 *ptr; + uint32 size; +}; +TypeStorage Pointers; - for(uint32 pos = 0; pos < size; pos++) - { - if(buf[pos] == '\n') - { - if(line.empty()) - continue; - while(line[0]==' ' || line[0]=='\t') - line.erase(0,1); - if(line.empty() || (line.length() > 1 && (line[0]=='#' || (line[0]=='/' && line[1]=='/'))) ) - { - line.clear(); - continue; - } - if(line[line.size()-1] == 13 || line[line.size()-1] == 10) // this fixes the annoying newline problems on windows + binary mode - line[line.size()-1] = 0; - if(line[0]=='[') - { - id=(uint32)toInt(line.c_str()+1); // start reading after '[' - sections++; - } - else - { - uint32 pos=line.find("="); - if(pos!=std::string::npos) - { - entry=stringToLower(line.substr(0,pos)); - value=line.substr(pos+1,line.length()-1); - _map[id].Set(entry,value); - } - // else invalid line, must have '=' - } - line.clear(); - } - else - line += buf[pos]; // fill up line until a newline is reached (see above) - } - return sections; +SCPDatabase::~SCPDatabase() +{ + DEBUG(logdebug("Deleting SCPDatabase '%s'",_name.c_str())); + DropAll(); } -bool SCPDatabase::HasField(uint32 id) +SCPDatabase::SCPDatabase() { - for(SCPFieldMap::iterator i = _map.begin(); i != _map.end(); i++) - if(i->first == id) - return true; - return false; + _stringbuf = NULL; + _intbuf = NULL; + _compact = false; } -bool SCPField::HasEntry(std::string e) +void SCPDatabase::DropAll(void) { - for(SCPEntryMap::iterator i = _map.begin(); i != _map.end(); i++) - { - std::string ch = i->first; - if(ch == e) - return true; - } - return false; + DropTextData(); + if(_stringbuf) + delete [] _stringbuf; + if(_intbuf) + delete [] _intbuf; + _indexes.clear(); + _indexes_reverse.clear(); + _fielddefs.clear(); + _stringbuf = NULL; + _intbuf = NULL; + _stringsize = 0; + _compact = false; } -std::string SCPField::GetString(std::string entry) +void SCPDatabase::DropTextData(void) { - //return HasEntry(entry) ? _map[entry] : ""; - return _map[entry]; + DEBUG(logdebug("Dropping plaintext parts of DB '%s'",_name.c_str())); + for(SCPSourceList::iterator it = sources.begin(); it != sources.end(); it++) + Pointers.Delete(*it); + sources.clear(); + fields.clear(); } -// note that this can take a while depending on the size of the database! -uint32 SCPDatabase::GetFieldByValue(std::string entry, std::string value) +void *SCPDatabase::GetPtr(uint32 index, char *entry) { - for(SCPFieldMap::iterator fm = _map.begin(); fm != _map.end(); fm++) - if(fm->second.HasEntry(entry) && fm->second.GetString(entry)==value) - return fm->first; - return uint32(-1); + std::map::iterator it = _indexes.find(index); + if(it == _indexes.end()) + return NULL; + std::map::iterator fi = _fielddefs.find(entry); + if(fi == _fielddefs.end()) + return NULL; + + uint32 target_row = _indexes[index]; + uint32 field_id = _fielddefs[entry].id; + return (void*)&_intbuf[(_fields_per_row * target_row) + field_id]; } -bool SCPDatabaseMgr::HasDB(std::string n) +void *SCPDatabase::GetPtrByField(uint32 index, uint32 entry) { - for(SCPDatabaseMap::iterator i = _map.begin(); i != _map.end(); i++) - if(i->first == n) - return true; - return false; + std::map::iterator it = _indexes.find(index); + if(it == _indexes.end()) + return NULL; + + uint32 target_row = _indexes[index]; + return (void*)&_intbuf[(_fields_per_row * target_row) + entry]; } -SCPDatabase& SCPDatabaseMgr::GetDB(std::string n) +uint32 SCPDatabase::GetFieldByUint32Value(char *entry, uint32 val) { - return _map[n]; + std::map::iterator fi = _fielddefs.find(entry); + if(fi == _fielddefs.end()) + return SCP_INVALID_INT; + + uint32 field_id = _fielddefs[entry].id; + return GetFieldByUint32Value(field_id,val); +} + +uint32 SCPDatabase::GetFieldByUint32Value(uint32 entry, uint32 val) +{ + for(uint32 row = 0; row < _rowcount; row++) + if(_intbuf[row * _fields_per_row + entry] == val) + return _indexes_reverse[row]; + return SCP_INVALID_INT; +} + +uint32 SCPDatabase::GetFieldByIntValue(char *entry, int32 val) +{ + std::map::iterator fi = _fielddefs.find(entry); + if(fi == _fielddefs.end()) + return SCP_INVALID_INT; + + uint32 field_id = _fielddefs[entry].id; + return GetFieldByIntValue(field_id,val); +} + +uint32 SCPDatabase::GetFieldByIntValue(uint32 entry, int32 val) +{ + for(uint32 row = 0; row < _rowcount; row++) + if((int)_intbuf[row * _fields_per_row + entry] == val) + return _indexes_reverse[row]; + return (int)SCP_INVALID_INT; +} + +uint32 SCPDatabase::GetFieldByStringValue(char *entry, char *val) +{ + std::map::iterator fi = _fielddefs.find(entry); + if(fi == _fielddefs.end()) + return SCP_INVALID_INT; + + uint32 field_id = _fielddefs[entry].id; + return GetFieldByStringValue(field_id,val); +} + +uint32 SCPDatabase::GetFieldByStringValue(uint32 entry, char *val) +{ + for(uint32 row = 0; row < _rowcount; row++) + if(!stricmp(GetStringByOffset(_intbuf[row * _fields_per_row + entry]), val)) + return row; + return SCP_INVALID_INT; +} + +uint32 SCPDatabase::GetFieldType(char *entry) +{ + std::map::iterator it = _fielddefs.find(entry); + if(it != _fielddefs.end()) + return _fielddefs[entry].type; + return SCP_INVALID_INT; +} + +uint32 SCPDatabase::GetFieldId(char *entry) +{ + std::map::iterator it = _fielddefs.find(entry); + if(it != _fielddefs.end()) + return _fielddefs[entry].id; + return SCP_INVALID_INT; +} + +SCPDatabase *SCPDatabaseMgr::GetDB(std::string n, bool create) +{ + return create ? _map.Get(n) : _map.GetNoCreate(n); } uint32 SCPDatabaseMgr::AutoLoadFile(char *fn) { - std::fstream fh; - uint32 size = GetFileSize(fn); - if(!size) - return 0; + char *buf; + uint32 size; - fh.open(fn,std::ios_base::in | std::ios_base::binary); - if( !fh.is_open() ) - return 0; + // check if file was loaded before; use memory data if this is the case + if(memblock *mb = Pointers.GetNoCreate(fn)) + { + size = mb->size; + buf = (char*)mb->ptr; + } + else // and if not, read the file from disk + { + std::fstream fh; + size = GetFileSize(fn); + if(!size) + return 0; - char *buf = new char[size]; + fh.open(fn,std::ios_base::in | std::ios_base::binary); + if( !fh.is_open() ) + return 0; - fh.read(buf,size); - fh.close(); + buf = new char[size]; - std::string line,dbname; + fh.read(buf,size); + fh.close(); + + // store the loaded file buffer so we can reuse it later if necessary + Pointers.Assign(fn, new memblock((uint8*)buf,size)); + } + + std::string line,dbname,entry,value; + SCPDatabase *db = NULL; + uint32 id = 0, sections = 0; for(uint32 pos = 0; pos < size; pos++) { - if(buf[pos] == '\n') + if(buf[pos] == '\n' || buf[pos] == 10 || buf[pos] == 13) { if(line.empty()) continue; - while(line[0]==' ' || line[0]=='\t') + while(line.size() && (line[0]==' ' || line[0]=='\t')) line.erase(0,1); - if(line[0] == '#') + uint32 eq = line.find("="); + if(eq != std::string::npos) { - uint32 eq = line.find("="); - if(eq != std::string::npos) + entry=stringToLower(line.substr(0,eq)); + value=line.substr(eq+1,line.length()-1); + + if(!stricmp(entry.c_str(),"#dbname") && value.size()) { - std::string info = stringToLower(line.substr(0,pos)); - std::string value = stringToLower(line.substr(pos+1,line.length()-1)); - if(info == "#dbname") - { - dbname = value; - break; - } + dbname = value; + db = GetDB(dbname,true); // create db if not existing } + else if(db) + db->fields[id][entry] = value; } + else if(line[0]=='[') + { + id=(uint32)toInt(line.c_str()+1); // start reading after '[' + sections++; + } + line.clear(); } else line += buf[pos]; } - delete [] buf; - - if(dbname.empty()) - return 0; - - uint32 sections = GetDB(dbname).LoadFromMem(buf,size); + db->sources.insert(fn); return sections; - } -// -- helper functions -- // +//////////////////////////////////////////////////////// +// SCP compiler +//////////////////////////////////////////////////////// -std::string SCPDatabaseMgr::GetZoneName(uint32 id) + +// check the datatype that will be used for this string value +uint32 SCPDatabaseMgr::GetDataTypeFromString(char *s) { - return GetDB("zone").GetField(id).GetString("name"); + bool isint = true, first = true; + for(;*s;s++) // check every char until \0 is reached + { + if(!isdigit(*s) && !(first && (*s=='+' || *s=='-'))) // if not in 0-9 or first beeing "+" or "-" it cant be int... + { + isint = false; + if(*s != '.') // and if the char beeing not int isnt a dot (3.1415), it cant be float either + return SCP_TYPE_STRING; + } + first = false; + } + return isint ? SCP_TYPE_INT : SCP_TYPE_FLOAT; } -std::string SCPDatabaseMgr::GetRaceName(uint32 id) +bool SCPDatabaseMgr::Compact(char *dbname, char *outfile) { - std::string r = GetDB("race").GetField(id).GetString("name"); - //if(r.empty()) - // r = raceName[id]; - return r; + logdebug("Compacting database '%s' into file '%s'", dbname, outfile); + SCPDatabase *db = GetDB(dbname); + if(!db || db->fields.empty() || db->sources.empty()) + { + logerror("Compact(\"%s\",\"%s\") failed, DB doesn't exist or is empty",dbname,outfile); + return false; + } + std::map fieldIdMap; + std::map idToSectionMap; + ByteBuffer stringdata(5000); + uint32 cur_idx, pass = 0; + std::string line; + uint32 section=0; + uint32 *membuf = NULL; // stores ints, floats and string offsets from ByteBuffer stringdata + uint32 blocksize; + std::string entry,value; + uint32 field_id; + + // some preparations + uint32 nStrings = 0, nRows = db->fields.size(), nFields; // pre-declared + stringdata << ""; // write an empty string so that offset 0 will always return empty string + + // the whole process is divided into 2 passes: + // - pass 0 autodetects the datatypes stored in the dirfferent entries (SCPFieldDef) + // - pass 1 creates the data field holding the values and string offsets, and also stuffs string values into the ByteBuffer + while(pass < 2) + { + cur_idx = 1; // stores the current index of the last entry added. index 0 is always field_id! + section = 0; // stores how many sections are done already + for(SCPFieldMap::iterator fmit = db->fields.begin(); fmit != db->fields.end(); fmit++) + { + SCPEntryMap& emap = fmit->second; + field_id = fmit->first; // stores the field id (e.g. "[154]" in the scp file) + idToSectionMap[field_id] = section; // since not every field id exists, store field id and its section number + // for faster lookup, less overhead, and smaller files + + // write the field id into row position 0 of the data field + if(pass == 1) + { + ASSERT(membuf != NULL); + uint32 pos = section * nFields; + ASSERT(pos < blocksize); + membuf[pos] = field_id; + } + + for(SCPEntryMap::iterator eit = emap.begin(); eit != emap.end(); eit++) + { + // "entry=value" in the scp file + entry = eit->first; + value = eit->second; + + // pass 0 - autodetect field types + if(pass == 0) + { + if(fieldIdMap.find(entry) == fieldIdMap.end()) + { + SCPFieldDef d; + d.id = cur_idx++; + d.type = GetDataTypeFromString((char*)value.c_str()); + fieldIdMap[entry] = d; + DEBUG(logdebug("Found new key: '%s' id: %u type: %s", entry.c_str(), d.id, gettypename(d.type) )); + } + else + { + SCPFieldDef& d = fieldIdMap[entry]; + uint32 _oldtype = d.type; + // int can be changed to float or string, float only to string. changing back not allowed. + if(d.type == SCP_TYPE_INT) + { + d.type = GetDataTypeFromString((char*)value.c_str()); + } + else if(d.type == SCP_TYPE_FLOAT) + { + uint32 newtype = GetDataTypeFromString((char*)value.c_str()); + if(newtype == SCP_TYPE_STRING) + d.type = newtype; + } + + if(_oldtype != d.type) + { + logdebug("Key '%s' id %u changed from %s to %s (field_id: %u)", entry.c_str(), d.id, gettypename(_oldtype), gettypename(d.type),field_id); + } + } + } + // pass 1 - create the data field + else if(pass == 1) + { + ASSERT(membuf != NULL); + SCPFieldDef d = fieldIdMap[entry]; + uint32 pos = (section * nFields) + d.id; + ASSERT(pos < blocksize); + if(d.type == SCP_TYPE_STRING) + { + membuf[pos] = stringdata.wpos(); + stringdata << value; + nStrings++; + } + else if(d.type == SCP_TYPE_INT) + { + membuf[pos] = atoi(value.c_str()); + } + else if(d.type == SCP_TYPE_FLOAT) + { + ((float*)membuf)[pos] = atof(value.c_str()); + } + } + } + section++; + } + // if the first pass is done, allocate the data field for the second pass + if(!pass) + { + nFields = fieldIdMap.size() + 1; // add the one field used for the field ID + ASSERT(section == nRows); + blocksize = nRows * nFields; // +1 because we store the field id here also + DEBUG(logdebug("SCP: allocating %u*%u = %u integers (%u bytes)",nRows,fieldIdMap.size()+1,blocksize, blocksize*sizeof(uint32))); + membuf = new uint32[blocksize]; + memset(membuf, 0, blocksize * sizeof(uint32)); + } + pass++; + } + + // used header fields, some are pre-declared above, if needed + uint32 offsMD5, nMD5, sizeMD5; + uint32 offsIndexes, nIndexes, sizeIndexes; + uint32 offsFields, sizeFields; + uint32 offsData; + uint32 offsStrings, sizeStrings; + + // MD5 hashes of source files + SCPSourceList& src = db->sources; + ByteBuffer md5buf; + nMD5 = 0; + for(SCPSourceList::iterator it = src.begin(); it != src.end(); it++) + { + memblock *mb = Pointers.GetNoCreate(*it); + if(!mb) + { + // if we reach this point there was really some big f*** up + logerror("SCP Compact: memblock for file '%s' doesn't exist",it->c_str()); + continue; + } + + MD5Hash md5; + md5.Update(mb->ptr,mb->size); + md5.Finalize(); + md5buf << *it; + md5buf.append(md5.GetDigest(),md5.GetLength()); + nMD5++; + } + sizeMD5 = md5buf.size(); + + // field types, sorted by IDs + ByteBuffer fieldbuf; + // put the entries and their type into ByteBuffer, sorted by their position in the membuf rows + // note that the first field in the data row is always the field id, so the values start from 1 + for(std::map::iterator itf = fieldIdMap.begin(); itf != fieldIdMap.end(); itf++) + { + fieldbuf << itf->first << itf->second.id << itf->second.type; // entry name, id, type. + } + sizeFields = fieldbuf.size(); + + // index -> ID lookup table, e.g. data with ID 500 will have field index 214, because some IDs in between are missing + // it *could* be calculated at load-time from the existing data field, but this way is faster when random-accessing the file itself + // (what we dont do anyway, for now) + ByteBuffer indexbuf; + for(std::map::iterator itx = idToSectionMap.begin(); itx != idToSectionMap.end(); itx++) + { + indexbuf << itx->first << itx->second; // field id; row number + } + nIndexes = idToSectionMap.size(); + sizeIndexes = indexbuf.size(); + + // string data + // -- most of it is handled somewhere above + sizeStrings = stringdata.size(); + + // precalc absolute offsets, header is 18 bytes large + offsMD5 = HEADER_SIZE; + offsIndexes = offsMD5 + sizeMD5; + offsFields = offsIndexes + sizeIndexes; + offsData = offsFields + sizeFields; + offsStrings = offsData + blocksize * sizeof(uint32); + + // buffer the file header + ByteBuffer hbuf; + hbuf.append("SCPC",4); // identifier + hbuf << (uint32)0; // flags, not yet used + hbuf << (uint32)0 << (uint32)0 << (uint32)0 << (uint32)0; // padding, not yet used + hbuf << offsMD5 << nMD5 << sizeMD5; + hbuf << offsIndexes << nIndexes << sizeIndexes; + hbuf << offsFields << nFields << sizeFields; + hbuf << offsData << section << blocksize * sizeof(uint32); + hbuf << offsStrings << nStrings << sizeStrings; + + FILE *fh = fopen(outfile,"wb"); + if(!fh) + return false; + if(fh) + { + fwrite(hbuf.contents(),hbuf.size(),1,fh); + if(sizeMD5) // just in case no md5sums are stored + fwrite(md5buf.contents(),sizeMD5,1,fh); + fwrite(indexbuf.contents(),sizeIndexes,1,fh); + fwrite(fieldbuf.contents(),sizeFields,1,fh); + fwrite(membuf,sizeof(uint32),blocksize,fh); + fwrite(stringdata.contents(),sizeStrings,1,fh); + } + fclose(fh); + + if(!db) + db = GetDB(dbname,true); // create if not exist + + db->_compact = true; + db->_name = dbname; + + // drop all data no longer needed if the database is compacted + db->DropTextData(); + + // we keep the membuf, since the compiled data are now usable as if loaded directly from a file + // associate it with the buffers used by the db accessing functions + db->_stringbuf = new char[sizeStrings]; + db->_stringsize = sizeStrings; + memcpy(db->_stringbuf,stringdata.contents(),sizeStrings); + db->_intbuf = membuf; // <<-- do NOT drop the membuf, its still used and will be deleted with ~SCPDatabase()!! + db->_fields_per_row = nFields; + db->_rowcount = nRows; + db->_indexes = idToSectionMap; + db->_fielddefs = fieldIdMap; + for(std::map::iterator it = idToSectionMap.begin(); it != idToSectionMap.end(); it++) + db->_indexes_reverse[it->second] = it->first; + + return true; } -std::string SCPDatabaseMgr::GetMapName(uint32 id) +uint32 SCPDatabaseMgr::SearchAndLoad(char *dbname, bool no_compiled) { - return GetDB("map").GetField(id).GetString("name"); + uint32 count = 0; + std::deque goodfiles; + + for(std::deque::iterator it = _paths.begin(); it != _paths.end(); it++) + { + std::deque files = GetFileList(*it); + sort(files.begin(),files.end()); // rough alphabetical sort + for(std::deque::iterator itf = files.begin(); itf != files.end(); itf++) + { + std::string& fn = *itf; + if(fn.length() < 5) + continue; + std::string filepath = *it + fn; + // check for special case: .ccp in this directory? load it and skip the rest + if(!no_compiled && !stricmp(std::string(dbname).append(".ccp").c_str(), fn.c_str())) + { + logdebug("Loading pre-compacted database '%s%s'", it->c_str(), fn.c_str()); + DropDB(dbname); // if sth got loaded before, remove that + // load SCC database file and skip rest + if(LoadCompactSCP((char*)filepath.c_str(), dbname)) + { + logdebug("Loaded '%s' -> %s, skipping scp files",filepath.c_str(),dbname); + return 1; + } + } + else if(!stricmp(fn.c_str() + fn.length() - 4, ".scp")) + { + // skip 0-byte files + if(GetFileSize(filepath.c_str())) + goodfiles.push_back(filepath); + } + } + } + + logdetail("Pre-compacted SCC file for '%s' invalid, creating from SCP (%u files total)",dbname,goodfiles.size()); + + for(std::deque::iterator it = goodfiles.begin(); it != goodfiles.end(); it++) + { + bool load_it = false; + std::fstream fh; + fh.open( it->c_str() , std::ios_base::in | std::ios_base::binary); + if( !fh.is_open() ) + continue; + + uint32 size = 1000; // search for #dbname tag in first 1000 bytes + char *buf = new char[size]; + memset(buf,0,size); + + fh.read(buf,size); + fh.close(); + + std::string line,dbn; + for(uint32 pos = 0; pos < size; pos++) + { + if(buf[pos] == '\n' || buf[pos] == 10 || buf[pos] == 13) + { + if(line.empty()) + continue; + while(line.size() && (line[0]==' ' || line[0]=='\t')) + line.erase(0,1); + if(line[0] == '#') + { + if(!strnicmp(line.c_str(),"#dbname=",8) && !stricmp(line.c_str()+8, dbname)) + { + load_it = true; + break; + } + } + line.clear(); + } + else + line += buf[pos]; + } + delete [] buf; + + if(load_it) + { + logdebug("File '%s' matching database '%s', loading", it->c_str(), dbname); + count++; + uint32 sections = AutoLoadFile((char*)it->c_str()); + } + } + + char fn[100]; + sprintf(fn,"./cache/%s.ccp",dbname); + Compact(dbname, fn); + + return count; } -std::string SCPDatabaseMgr::GetClassName_(uint32 id) +void SCPDatabaseMgr::AddSearchPath(char *path) { - std::string r = GetDB("class").GetField(id).GetString("name"); - //if(r.empty()) - // r = className[id]; - return r; + std::string p; + + // normalize path, use '/' instead of '\'. needed for that check below + uint32 len = strlen(path); + for(uint32 i = 0; i < len; i++) + { + if(path[i] == '\\') + p += '/'; + else + p += path[i]; + } + + if(p[p.size()-1] != '/') + p += '/'; + for(std::deque::iterator it = _paths.begin(); it != _paths.end(); it++) + { + // windows doesnt care about UPPER/lowercase, while *nix does; + // a path shouldnt be added twice or unexpected behavior is likely to occur +#if PLATFORM == PLATFORM_WIN32 + if(!stricmp(p.c_str(), it->c_str())) + return; +#else + if(p == *it) + return; +#endif + } + + _paths.push_back(p); } -std::string SCPDatabaseMgr::GetGenderName(uint32 id) +bool SCPDatabaseMgr::LoadCompactSCP(char *fn, char *dbname) { - return GetDB("gender").GetField(id).GetString("name"); + uint32 filesize = GetFileSize(fn); + if(filesize < HEADER_SIZE) + { + logerror("Database file '%s' is too small!",fn); + return false; + } + std::fstream fh; + fh.open(fn, std::ios_base::in | std::ios_base::binary); + if(!fh.is_open()) + { + logerror("Error opening '%s'",fn); + return false; + } + + ByteBuffer bb; + bb.resize(filesize); + fh.read((char*)bb.contents(), filesize); + fh.close(); + + char tag[4]; + uint32 flags, padding[4]; + uint32 offsMD5, nMD5, sizeMD5; + uint32 offsIndexes, nIndexes, sizeIndexes; + uint32 offsFields, nFields, sizeFields; + uint32 offsData, nRows, sizeData; + uint32 offsStrings, nStrings, sizeStrings; + + bb.read((uint8*)&tag[0],4); + if(memcmp(tag,"SCPC",4)) + { + logerror("'%s' is not a compact database file!",fn); + return false; + } + bb >> flags; + bb >> padding[0] >> padding[1] >> padding[2] >> padding[3]; + bb >> offsMD5 >> nMD5 >> sizeMD5; + bb >> offsIndexes >> nIndexes >> sizeIndexes; + bb >> offsFields >> nFields >> sizeFields; + bb >> offsData >> nRows >> sizeData; + bb >> offsStrings >> nStrings >> sizeStrings; + + SCPDatabase *db = GetDB(dbname,true); + db->_name = dbname; + db->_compact = true; + + ByteBuffer md5buf(sizeMD5); + md5buf.resize(sizeMD5); + // read MD5 block + bb.rpos(offsMD5); + if(bb.rpos() == offsMD5) + bb.read((uint8*)md5buf.contents(),sizeMD5); + else + { + logerror("'%s' has wrong MD5 offset, can't load",fn); + return false; + } + + for(uint32 i = 0; i < nMD5; i++) + { + // read filename and MD5 hash from compiled database + uint8 buf[MD5_DIGEST_LENGTH]; + std::string refFn; + md5buf >> refFn; + md5buf.read(buf,MD5_DIGEST_LENGTH); + + // load the file referred to + uint32 refFileSize = GetFileSize(refFn.c_str()); + FILE *refFile = fopen(refFn.c_str(), "rb"); + if(!refFile) + { + logdebug("Not loading '%s', file doesn't exist",fn); + return false; + } + uint8 *refFileBuf = new uint8[refFileSize]; + fread(refFileBuf,sizeof(uint8),refFileSize,refFile); + fclose(refFile); + db->sources.insert(refFn); + Pointers.Assign(refFn, new memblock(refFileBuf,refFileSize)); + MD5Hash md5; + md5.Update(refFileBuf,refFileSize); + md5.Finalize(); + if(memcmp(buf, md5.GetDigest(), MD5_DIGEST_LENGTH)) + { + logdebug("MD5-check: '%s' has changed!", refFn.c_str()); + return false; + } + else + { + logdebug("MD5-check: '%s' -> OK",refFn.c_str()); + } + } + + // everything good so far? we reached this point? then its likely that the rest of the file is ok, alloc remaining buffers + ByteBuffer indexbuf(sizeIndexes); + ByteBuffer fieldsbuf(sizeFields); + indexbuf.resize(sizeIndexes); + fieldsbuf.resize(sizeFields); + + // read indexes block + bb.rpos(offsIndexes); + if(bb.rpos() == offsIndexes) + bb.read((uint8*)indexbuf.contents(),sizeIndexes); + else + { + logerror("'%s' has wrong indexes offset, can't load",fn); + return false; + } + + // read field definitions buf + bb.rpos(offsFields); + if(bb.rpos() == offsFields) + bb.read((uint8*)fieldsbuf.contents(),sizeFields); + else + { + logerror("'%s' has wrong field defs offset, can't load",fn); + return false; + } + + // main data and string blocks follow below + + for(uint32 i = 0; i < nIndexes; i++) + { + uint32 field_id, row; + indexbuf >> field_id >> row; + db->_indexes[field_id] = row; + db->_indexes_reverse[row] = field_id; + } + + for(uint32 i = 0; i < nFields - 1; i++) // the first field (index column) is never written to the file! + { + SCPFieldDef fieldd; + std::string fieldn; + fieldsbuf >> fieldn >> fieldd.id >> fieldd.type; + db->_fielddefs[fieldn] = fieldd; + } + + // read main data block + ASSERT(nRows * nFields == sizeData / sizeof(uint32)); + bb.rpos(offsData); + if(bb.rpos() == offsData) + { + db->_intbuf = new uint32[nRows * nFields]; + bb.read((uint8*)db->_intbuf, sizeData); // load this somewhat fast and without a for loop + } + else + { + logerror("'%s' has wrong data offset, can't load",fn); + return false; + } + + // read strings + bb.rpos(offsStrings); + if(bb.rpos() == offsStrings) + { + db->_stringbuf = new char[sizeStrings]; + bb.read((uint8*)db->_stringbuf,sizeStrings); + } + else + { + logerror("'%s' has wrong strings offset, can't load",fn); + return false; + } + db->_stringsize = sizeStrings; + db->_rowcount = nRows; + db->_fields_per_row = nFields; + + db->DropTextData(); // delete pointers to file content created at md5 comparison + + logdebug("'%s' loaded successfully",fn); + + return true; } -std::string SCPDatabaseMgr::GetLangName(uint32 id) +// used only for debugging +void SCPDatabase::DumpStructureToFile(char *fn) { - std::string r = GetDB("language").GetField(id).GetString("name"); - //if(r.empty()) - // r = LookupName(id,langNames); - return r; + std::ofstream f; + f.open(fn); + if(!f.is_open()) + return; + + uint32 *ftype = new uint32[_fields_per_row]; + ftype[0] = SCP_TYPE_INT; + + f << "Fields: (0 is always index field)\n"; + for(std::map::iterator it = _fielddefs.begin(); it != _fielddefs.end(); it++) + { + f << "-> Name: " << it->first << ", ID: " << it->second.id << ", type: " << gettypename(it->second.type) << "\n"; + ftype[it->second.id] = it->second.type; + } + f << "\n"; + + for(uint32 row = 0; row < _rowcount; row++) + { + for(uint32 column = 0; column < _fields_per_row; column++) + { + if(ftype[column] == SCP_TYPE_INT) + f << *((int*)&_intbuf[row * _fields_per_row + column]) << "\t"; + else if(ftype[column] == SCP_TYPE_FLOAT) + f << *((float*)&_intbuf[row * _fields_per_row + column]) << "\t"; + else + f << "S_" << _intbuf[row * _fields_per_row + column] << "\t"; + } + f << "\n"; + } + + f << "\nStrings:\n"; + for(uint32 i = 0; i < _stringsize; i++) + { + if(!_stringbuf[i]) + { + i++; + if(i >= _stringsize) + break; + f << "\n" << i << ": "; + } + f << _stringbuf[i]; + } } + + + + + diff --git a/src/Client/SCPDatabase.h b/src/Client/SCPDatabase.h index 01e0bc1..84c9906 100644 --- a/src/Client/SCPDatabase.h +++ b/src/Client/SCPDatabase.h @@ -1,113 +1,106 @@ #ifndef _SCPDATABASE_H #define _SCPDATABASE_H -#include +#include "DefScript/TypeStorage.h" +#include -/* - * Some preparations for compiled databases. i will continue this later. [FG] - -enum SCPTypes +enum SCPFieldTypes { - SCP_TYPE_STRING = 0, - SCP_TYPE_INT, - SCP_TYPE_UINT, - SCP_TYPE_FLOAT + SCP_TYPE_INT = 0, + SCP_TYPE_FLOAT = 1, + SCP_TYPE_STRING = 2 }; -class SCPEntry +struct SCPFieldDef { -private: - char *str; - -public: - - SCPEntry() { str = NULL; } - ~SCPEntry() { if(str) delete [] str; } - - union - { - int32 intvalue - uint32 uintvalue; - float floatvalue; - }; - - inline char *GetString(uint8 type) - { - if(str) - return str; - else - { - char buf[25]; - char *fmt; - switch (type) - { - case SCP_TYPE_INT: sprintf(buf,"%d",intvalue); break; - case SCP_TYPE_UINT: sprintf(buf,"%u",uintvalue); break; - case SCP_TYPE_FLOAT: sprintf(buf,"%f",floatvalue); break; - } - str = new char[strlen(buf) + 1]; - memcpy(str,buf,strlen(buf) + 1); - return str; - } - } + uint32 id; + uint8 type; }; -*/ +#define SCP_INVALID_INT 0xFFFFFFFF typedef std::map SCPEntryMap; - -class SCPField -{ -public: - std::string GetString(std::string); - inline uint64 GetInteger(std::string entry) { return toInt(GetString(entry)); } - inline double GetDouble(std::string entry) { return strtod(GetString(entry).c_str(),NULL); } - inline void Set(std::string entry,std::string value) { _map[entry]=value; } - bool HasEntry(std::string); - -private: - SCPEntryMap _map; -}; - -typedef std::map SCPFieldMap; - +typedef std::map SCPFieldMap; +typedef std::set SCPSourceList; class SCPDatabase { + friend class SCPDatabaseMgr; public: - inline SCPField& GetField(uint32 id) { return _map[id]; } - bool HasField(uint32 id); - uint32 LoadFromFile(char*); - uint32 LoadFromMem(char*,uint32); - uint32 GetFieldByValue(std::string entry, std::string value); + SCPDatabase(); + ~SCPDatabase(); + // if the database is compacted, do not allow any modification from outside + SCPSourceList *GetSources(void) { return _compact ? NULL : &sources; } + SCPFieldMap *GetFields(void) { return _compact ? NULL : &fields; } + inline bool IsCompact(void) { return _compact; } + inline std::string GetName(void) { return _name; } + void DropAll(void); + void DropTextData(void); + + // access funcs + void *GetPtr(uint32 index, char *entry); + void *GetPtrByField(uint32 index, uint32 entry); + inline char *GetStringByOffset(uint32 offs) { return (offs < _stringsize ? _stringbuf + offs : ""); } + inline char *GetString(uint32 index, char *entry) { return GetStringByOffset(GetUint32(index,entry)); } + inline char *GetString(uint32 index, uint32 entry) { return GetStringByOffset(GetUint32(index,entry)); } + inline uint32 GetUint32(uint32 index, char *entry) { uint32 *t = (uint32*)GetPtr(index,entry); return t ? *t : 0; } + inline uint32 GetUint32(uint32 index, uint32 entry) { uint32 *t = (uint32*)GetPtrByField(index,entry); return t ? *t : 0; } + inline int32 GetInt(uint32 index, char *entry) { int32 *t = (int32*)GetPtr(index,entry); return t ? *t : 0; } + inline int32 GetInt(uint32 index, uint32 entry) { int32 *t = (int32*)GetPtrByField(index,entry); return t ? *t : 0; } + inline float GetFloat(uint32 index, char *entry) { float *t = (float*)GetPtr(index,entry); return t ? *t : 0; } + inline float GetFloat(uint32 index, uint32 entry) { float *t = (float*)GetPtrByField(index,entry); return t ? *t : 0; } + uint32 GetFieldType(char *entry); + uint32 GetFieldId(char *entry); + inline void *GetRowByIndex(uint32 index) { return GetPtrByField(index,0); } + uint32 GetFieldByUint32Value(char *entry, uint32 val); + uint32 GetFieldByUint32Value(uint32 entry, uint32 val); + uint32 GetFieldByIntValue(char *entry, int32 val); + uint32 GetFieldByIntValue(uint32 entry, int32 val); + uint32 GetFieldByStringValue(char *entry, char *val); + uint32 GetFieldByStringValue(uint32 entry, char *val); + // float value lookup not necessary + inline uint32 GetFieldsCount(void) { return _fields_per_row; } + inline uint32 GetRowsCount(void) { return _rowcount; } + + + void DumpStructureToFile(char *fn); private: - SCPFieldMap _map; + // text data related + SCPSourceList sources; + SCPFieldMap fields; + // binary data related + bool _compact; + std::string _name; + uint32 _rowcount; + uint32 _fields_per_row; + char *_stringbuf; + uint32 _stringsize; + uint32 *_intbuf; + std::map _indexes, _indexes_reverse; // stores index-to-rowID, rowID-to-index + std::map _fielddefs; }; -typedef std::map SCPDatabaseMap; +typedef TypeStorage SCPDatabaseMap; + class SCPDatabaseMgr { + friend class SCPDatabase; public: - bool HasDB(std::string); - SCPDatabase& GetDB(std::string); + SCPDatabase *GetDB(std::string n, bool create = false); uint32 AutoLoadFile(char *fn); - inline void DropDB(std::string s) { _map.erase(stringToLower(s)); } - - ////////////////////// - // helper functions // - ////////////////////// - std::string GetZoneName(uint32 id); - std::string GetRaceName(uint32 id); - std::string GetClassName_(uint32 id); - std::string GetGenderName(uint32 id); - std::string GetMapName(uint32 id); - std::string GetLangName(uint32 id); + inline void DropDB(std::string s) { _map.Delete(stringToLower(s)); } + bool Compact(char *dbname, char *outfile); + static uint32 GetDataTypeFromString(char *s); + uint32 SearchAndLoad(char*,bool); + void AddSearchPath(char*); + bool LoadCompactSCP(char*, char*); private: SCPDatabaseMap _map; + std::deque _paths; }; diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index c91c060..b6a6243 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -577,15 +577,30 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket) } bool char_found=false; + SCPDatabase *zonedb = GetDBMgr().GetDB("zone"), + *racedb = GetDBMgr().GetDB("race"), + *mapdb = GetDBMgr().GetDB("map"), + *classdb = GetDBMgr().GetDB("class"); + char *zonename, *racename, *mapname, *classname; + for(unsigned int i=0;iGetString(plr[i]._zoneId, "name"); + if(racedb) + racename = racedb->GetString(plr[i]._race, "name"); + if(mapdb) + mapname = mapdb->GetString(plr[i]._mapId, "name"); + if(classdb) + classname = classdb->GetString(plr[i]._class, "name"); + logcustom(0,LGREEN,"## %s (%u) [%s/%s] Map: %s; Zone: %s", plr[i]._name.c_str(), plr[i]._level, - GetDBMgr().GetRaceName(plr[i]._race).c_str(), - GetDBMgr().GetClassName_(plr[i]._class).c_str(), - GetDBMgr().GetMapName(plr[i]._mapId).c_str(), - GetDBMgr().GetZoneName(plr[i]._zoneId).c_str()); + racename, + classname, + mapname, + zonename); logdetail("-> coords: map=%u zone=%u x=%f y=%f z=%f", plr[i]._mapId,plr[i]._zoneId,plr[i]._x,plr[i]._y,plr[i]._z); @@ -683,8 +698,10 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) } recvPacket >> target_guid >> msglen >> msg; - std::string langname = GetDBMgr().GetLangName(lang); - const char* ln = langname.c_str(); + SCPDatabase *langdb = GetDBMgr().GetDB("language"); + const char* ln = ""; + if(langdb) + langdb->GetString(lang,"name"); std::string name; if(type == CHAT_MSG_MONSTER_SAY) @@ -1147,9 +1164,9 @@ void WorldSession::_HandleTextEmoteOpcode(WorldPacket& recvPacket) logdebug(I64FMT " Emote: name=%s text=%u variation=%i len=%u",guid,name.c_str(),emotetext,emotev,namelen); SCPDatabaseMgr& dbmgr = GetInstance()->dbmgr; - if(dbmgr.HasDB("emote")) + SCPDatabase *emotedb = dbmgr.GetDB("emote"); + if(emotedb) { - SCPDatabase& db = dbmgr.GetDB("emote"); std::string target,target2; bool targeted=false; // if the emote is directed to anyone around or a specific target bool targeted_me=false; // if the emote was targeted to us if it was targeted @@ -1196,13 +1213,13 @@ void WorldSession::_HandleTextEmoteOpcode(WorldPacket& recvPacket) target += "general"; // not all emotes have a female version, so check if there is one in the database - if(female && db.GetField(emotetext).HasEntry(target + "female")) + if(female && emotedb->GetFieldId((char*)(target + "female").c_str()) != SCP_INVALID_INT) target += "female"; logdebug("Looking up 'emote' SCP field %u entry '%s'",emotetext,target.c_str()); std::string etext; - etext = db.GetField(emotetext).GetString(target); + etext = emotedb->GetString(emotetext,(char*)target.c_str()); char out[300]; // should be enough @@ -1278,9 +1295,16 @@ void WorldSession::_HandleWhoOpcode(WorldPacket& recvPacket) std::string zonename; memset(classname,0,sizeof(classname)); memset(racename,0,sizeof(racename)); - zonename = db.GetZoneName(wle.zoneId); - strcpy(classname, db.GetClassName_(wle.classId).c_str()); - strcpy(racename, db.GetRaceName(wle.raceId).c_str()); + + SCPDatabase *zonedb = db.GetDB("zone"), + *racedb = db.GetDB("race"), + *classdb = db.GetDB("class"); + if(zonedb) + zonename = zonedb->GetString(wle.zoneId, "name"); + if(racedb) + strcpy(racename,racedb->GetString(wle.raceId, "name")); + if(classdb) + strcpy(classname,classdb->GetString(wle.classId, "name")); for(uint8 i = strlen(classname); strlen(classname) < 10; i++) classname[i] = ' '; diff --git a/src/PseuWoW.vcproj b/src/PseuWoW.vcproj index 4ad53ea..1182a2f 100644 --- a/src/PseuWoW.vcproj +++ b/src/PseuWoW.vcproj @@ -207,9 +207,6 @@ - - diff --git a/src/shared/ByteBuffer.h b/src/shared/ByteBuffer.h index d46f2e7..4d16c3c 100644 --- a/src/shared/ByteBuffer.h +++ b/src/shared/ByteBuffer.h @@ -181,7 +181,7 @@ class ByteBuffer size_t rpos(size_t rpos) { - _rpos = rpos; + _rpos = rpos < _storage.capacity() ? rpos : _storage.capacity(); return _rpos; }; @@ -192,7 +192,7 @@ class ByteBuffer size_t wpos(size_t wpos) { - _wpos = wpos; + _wpos = wpos < _storage.capacity() ? wpos : _storage.capacity(); return _wpos; }