From 3100f68a3016333f17873bd5022e92b0f0753abc Mon Sep 17 00:00:00 2001 From: "False.Genesis" Date: Wed, 1 Aug 2007 19:09:17 +0000 Subject: [PATCH] last changes before 2.1.3: * added script to support /me-like emotes (scriptname is "me") * changed the permission system: now a script cant be used as game command f no permission is explicitly set * implemented threadsafe CLI queue to solve crashes with short-intervalled events that ran on 2 threads * fixed name return at "getitemprotovalue" script * iplemented DrawObject class and a Mgr for those objects; they will ease object drawing once implemented. the Mgr works under control of the GUI thread and is threadsafe. * implemented auto-loading of SCP files if a name-tag is present somewhere in the file ("#dbname=...") and no explicit db name was passed to "loadscp" script. * changed internal ObjMgr storage to std::map (instead of list) for faster access * fixed call of "_enterworld" script * fixed handling of MyCharacter(), which could cause crashes after newly changes * fixed GetFileList() func in tools.cpp (this fixes also related "lgetfiles" script func). now it will only parse files, not directories. might still need some fixing for linux. --- bin/_startup.def | 46 +-- bin/scripts/__core_chat.def | 51 ++- bin/scripts/__core_func.def | 42 ++- bin/scripts/__core_funstuff.def | 133 ++++---- bin/scripts/__core_internal.def | 6 + bin/scripts/__core_list_extensions.def | 24 +- bin/scripts/__core_wrappers.def | 1 + bin/scripts/_nopermission.def | 4 +- bin/scripts/_onwhisper.def | 2 - src/Client/Cli.cpp | 23 +- src/Client/DefScript/VarSet.cpp | 2 +- src/Client/DefScriptInterface.cpp | 102 +++--- src/Client/GUI/DrawObjMgr.cpp | 67 ++++ src/Client/GUI/DrawObjMgr.h | 27 ++ src/Client/GUI/DrawObject.cpp | 21 ++ src/Client/GUI/DrawObject.h | 23 ++ src/Client/GUI/PseuGUI.cpp | 248 ++++++++------- src/Client/GUI/PseuGUI.h | 14 +- src/Client/PseuWoW.cpp | 110 ++++--- src/Client/PseuWoW.h | 134 ++++---- src/Client/SCPDatabase.cpp | 101 +++++- src/Client/SCPDatabase.h | 66 +++- src/Client/World/ObjMgr.cpp | 48 ++- src/Client/World/ObjMgr.h | 10 +- src/Client/World/Player.cpp | 6 + src/Client/World/Player.h | 1 + src/Client/World/UpdateData.cpp | 379 +++++++++++----------- src/Client/World/WorldSession.cpp | 415 +++++++++++++------------ src/PseuWoW.vcproj | 12 + src/shared/MapTile.h | 9 +- src/shared/tools.cpp | 12 +- 31 files changed, 1315 insertions(+), 824 deletions(-) create mode 100644 src/Client/GUI/DrawObjMgr.cpp create mode 100644 src/Client/GUI/DrawObjMgr.h create mode 100644 src/Client/GUI/DrawObject.cpp create mode 100644 src/Client/GUI/DrawObject.h diff --git a/bin/_startup.def b/bin/_startup.def index b97df35..bebf7ee 100644 --- a/bin/_startup.def +++ b/bin/_startup.def @@ -1,25 +1,31 @@ -#permission=255 - // PSEUWOW DEF_SCRIPT STARTUP FILE -LOG * DefScript StartUp [${@version_short}]... +// this is for debugging which scripts are loaded +// set to false to disable output +SET,LoadDebug true -// first, load all scripts in patch 'scripts' with extension .def +LOG *** DefScript StartUp [${@version_short}]... + +// first, load all scripts in path 'scripts' with extension .def SET,fcount ?{LGETFILES,scriptlist,def scripts} LSORT scriptlist -LOGDETAIL * Loading ${fcount} scripts. +LOG *** Loading ${fcount} script files. // iterate over all files and load them; if counter i is equal to the amount of files we are done. SET,i 0 +SET,errors 0 LOOP - IF ?{EQUAL,${i} ${fcount}} - EXITLOOP - ENDIF - SET,fn ./scripts/?{LINDEX,scriptlist ${i}} - LOG *** Loading script file [${fn}] - IF ?{NOT ?{LOADDEF ${fn}}} - LOGERROR Can't load script [${fn}] - ENDIF - ADD,i 1 + IF ?{EQUAL,${i} ${fcount}} + EXITLOOP + ENDIF + SET,fn ./scripts/?{LINDEX,scriptlist ${i}} + IF ?{AND,?{IsSet LoadDebug} ${LoadDebug}} + LOG * Loading script file [${fn}] + ENDIF + IF ?{NOT ?{LOADDEF ${fn}}} + LOGERROR * Error loading [${fn}] + ADD,errors 1 + ENDIF + ADD,i 1 ENDLOOP UNSET tmp @@ -28,13 +34,17 @@ UNSET i UNSET fn LDELETE scriptlist +IF ?{NOT ${errors}} + LOG *** All files loaded without errors. +ELSE + LOG *** All files loaded, ${errors} errors. +ENDIF +UNSET errors + // loads & applies the configuration CONFIG -// set permissions for internal functions -INTERNAL_PERM - -// Load some SCP files +// Load some SCP files LOADALLSCP // do more stuff here in future... diff --git a/bin/scripts/__core_chat.def b/bin/scripts/__core_chat.def index 834a5dc..57eb262 100644 --- a/bin/scripts/__core_chat.def +++ b/bin/scripts/__core_chat.def @@ -51,13 +51,13 @@ UNSET msg //----------------------------------------------------------- // is the char equal to the char we use for commands? does the player have a permission lvl below 255? IF ?{AND,?{string_is_command ${@def}} ?{SMALLER,?{GETPLAYERPERM ${@thiscmd_name}} 255}} - // yes: say a warning and the command the player wanted to use - SAY ${@thiscmd_name}: no permission to use commands [${@def}] - RETURN false + // yes: say a warning and the command the player wanted to use + SAY ${@thiscmd_name}: no permission to use commands [${@def}] + RETURN false ELSE - // no: say the text as usual. - SAY,{${@0}} ${@def} - RETURN true + // no: say the text as usual. + SAY,{${@0}} ${@def} + RETURN true ENDIF @@ -140,10 +140,10 @@ SET,vl ${@0} DEFAULT,vl 0 IF ?{NOT ?{ISSET ${vn}}} - SAY,{${vl}} * Var '${@def}' not defined. + SAY,{${vl}} * Var '${@def}' not defined. ELSE - SET,vv ${${vn}} - SAY,{${vl}} * Var '${@def}' = '${vv}' + SET,vv ${${vn}} + SAY,{${vl}} * Var '${@def}' = '${vv}' ENDIF UNSET vv @@ -200,11 +200,30 @@ UNSET msg //----------------------------------------------------------- // is the char equal to the char we use for commands? does the player have a permission lvl below 255? IF ?{AND,?{string_is_command ${@def}} ?{SMALLER,?{GETPLAYERPERM ${@thiscmd_name}} 255}} - // yes: say a warning and the command the player wanted to use - YELL ${@thiscmd_name}: no permission to use commands [${@def}] - RETURN false + // yes: say a warning and the command the player wanted to use + YELL ${@thiscmd_name}: no permission to use commands [${@def}] + RETURN false ELSE - // no: say the text as usual. - YELL,{${@0}} ${@def} - RETURN true -ENDIF \ No newline at end of file + // no: say the text as usual. + YELL,{${@0}} ${@def} + RETURN true +ENDIF + + +//---------------------------------------------------------- +#script=me +#permission=0 +//---------------------------------------------------------- +// Send text emote. example: "me feels lolo" will result in "Pseuwow feels lolo" at other clients +SET,lang ${@0} +SET,msg ${@def} + +DEFAULT,#DEFAULTLANG ?{GETSCPVALUE,race,{${@myrace}} faction} +DEFAULT,lang ${#DEFAULTLANG} + +LOGDEBUG * Me ${msg} (in lang ${lang}) + +SENDCHATMESSAGE,8,${lang},{${msg}} +UNSET lang +UNSET msg + diff --git a/bin/scripts/__core_func.def b/bin/scripts/__core_func.def index 1594e5a..bd4db1b 100644 --- a/bin/scripts/__core_func.def +++ b/bin/scripts/__core_func.def @@ -1,12 +1,11 @@ // core functions. required by other scripts to run! #onload - log * Loading core scripts... + log * Loading core scripts... #/onload //-------------------------------------------------------- #script=append -#permission=255 //-------------------------------------------------------- // usage: append text to a string. // args: @@ -28,9 +27,9 @@ UNSET v #permission=255 //-------------------------------------------------------- if ?{fileexists ${@def}} - loadscp,{${@0}} ${@def} + loadscp,{${@0}} ${@def} else - logdebug skipped loading of non-existent file '${@def}' + logdebug skipped loading of non-existent file '${@def}' endif @@ -53,13 +52,13 @@ LOADSCP,race data/scp/race.scp // load extended databases if present. EXLOADSCP,sound data/scp/sound.scp EXLOADSCP,emote data/scp/emote.scp +EXLOADSCP,area data/scp/area.scp LOG * SCP loaded. //------------------------------------------------- #script=string_is_command -#permission=255 //------------------------------------------------- // purpose: detect if @def might be a server command. @@ -71,8 +70,8 @@ SET,c ?{SUBSTR,1 ${@def}} // does the char list contain our first char? if yes it can trigger a server command. if ?{lcontains,#CMDCHARLIST ${c}} - unset c - return true + unset c + return true endif unset c return false @@ -80,7 +79,6 @@ return false //-------------------------------------------------------- #script=normalize_name -#permission=255 //-------------------------------------------------------- // uppercases first char, lowercases rest set,name ?{uppercase ?{substr,1 ${@def}}} @@ -91,14 +89,13 @@ return ${name} //--------------------------------------------------------- #script=globname -#permission=255 //--------------------------------------------------------- // purpose: returns the global name of a variable // args: @def: var name, @0 (optional): name of the intended parent func set,c ?{substr,1 ${@def}} // it is a global var if the varname starts with # or there is no caller script if ?{or,?{equal,# ${c}} ?{not ${@caller}}} - return ${@def} + return ${@def} endif set,top ${@0} default,top ${@caller} @@ -107,7 +104,6 @@ return #${top}::${@def} //--------------------------------------------------------- #script=getvar -#permission=255 //--------------------------------------------------------- // purpose: returns the value of a variable. if the variable hasnt been set return empty string. set,top ${@caller} @@ -116,8 +112,30 @@ set,v ?{globname,${top} ${@def}} unset top out getvar: v=${v} -> ${${v}} if ?{isset ${v}} - return ${${v}} + return ${${v}} endif return +//--------------------------------------------------------- +#script=reverse +//--------------------------------------------------------- +// purpose: reverse a srtring +// args: @def: string to reverse +// returns: reversed string + +set,outstr +set,elems ?{lsplit,mylist ${@def}} +set,i ${elems} +loop + sub,i 1 + if ?{equal,${i} -1} + exitloop + endif + append,outstr ?{lindex,mylist ${i}} +endloop +ldelete mylist +return ${outstr} + + + diff --git a/bin/scripts/__core_funstuff.def b/bin/scripts/__core_funstuff.def index 312fb48..70c7f6d 100644 --- a/bin/scripts/__core_funstuff.def +++ b/bin/scripts/__core_funstuff.def @@ -10,21 +10,21 @@ // we can use this script only if we are in the world if ?{not ${@inworld}} - logerror Can't slap anything if i am not in the world! - return + logerror Can't slap anything if i am not in the world! + return endif // normalize player name. first char uppercased, rest lowercased. set,name ?{normalize_name ${@def}} -// target the player. if targeting was successful, cast spell "Knockback 500". +// target the player. if targeting was successful, cast spell "Knockback 500". set,t ?{target ${name}} if ${t} - logdebug slapping player '${name}' - castspell 11027 - target + logdebug slapping player '${name}' + castspell 11027 + target else - logerror Can't target player '${name}' + logerror Can't target player '${name}' endif unset name @@ -35,15 +35,14 @@ return ${t} //------------------------------------------------ #script=toleet -#permission=255 //------------------------------------------------ // purpose: convert any text into leetspeak [1337sp34k] // args: @def: the text to convert // returns: leetspeak^^ #onload - // this can be used by other scripts to check if we have loaded this script - set,#HAVE_LEET true + // this can be used by other scripts to check if we have loaded this script + set,#HAVE_LEET true #endonload // empty the string where the leet will be stored @@ -55,65 +54,65 @@ set,x 0 loop - // check if we have reached the end of the string - if ?{bigger,${x} ${l}} - exitloop - endif + // check if we have reached the end of the string + if ?{bigger,${x} ${l}} + exitloop + endif - // c stores current char (@def at position x); c2 is the same char but always lowercased - set,c ?{substr,1,${x} ${@def}} - set,c2 ?{lowercase ${c}} + // c stores current char (@def at position x); c2 is the same char but always lowercased + set,c ?{substr,1,${x} ${@def}} + set,c2 ?{lowercase ${c}} - // conversion functions: - - // note that "+" is a variable name here! - // it will store the "new" char if c/c2 could be converted - - if ?{equal,${c2} a} - set,+ 4 - endif - if ?{equal,${c2} e} - set,+ 3 - endif - if ?{equal,${c2} i} - set,+ ! - endif - if ?{equal,${c2} l} - set,+ 1 - endif - if ?{equal,${c2} t} - set,+ 7 - endif - if ?{equal,${c2} s} - set,+ 5 - endif - if ?{equal,${c2} o} - set,+ 0 - endif - if ?{equal,${c2} f} - set,+ ph - endif - if ?{equal,${c2} h} - set,+ # - endif - if ?{equal,${c} Z} - set,+ 7 - endif - if ?{equal,${c} R} - set,+ 2 - endif - if ?{equal,${c} B} - set,+ <3 - endif - - // if var "+" is still empty, default it to our current char - default,+ ${c} - // and append it to the final output - append,str ${+} - // finally delete it again - unset + - // and increase the counter by 1 - add,x 1 + // conversion functions: + + // note that "+" is a variable name here! + // it will store the "new" char if c/c2 could be converted + + if ?{equal,${c2} a} + set,+ 4 + endif + if ?{equal,${c2} e} + set,+ 3 + endif + if ?{equal,${c2} i} + set,+ ! + endif + if ?{equal,${c2} l} + set,+ 1 + endif + if ?{equal,${c2} t} + set,+ 7 + endif + if ?{equal,${c2} s} + set,+ 5 + endif + if ?{equal,${c2} o} + set,+ 0 + endif + if ?{equal,${c2} f} + set,+ ph + endif + if ?{equal,${c2} h} + set,+ # + endif + if ?{equal,${c} Z} + set,+ 7 + endif + if ?{equal,${c} R} + set,+ 2 + endif + if ?{equal,${c} B} + set,+ <3 + endif + + // if var "+" is still empty, default it to our current char + default,+ ${c} + // and append it to the final output + append,str ${+} + // finally delete it again + unset + + // and increase the counter by 1 + add,x 1 endloop unset l diff --git a/bin/scripts/__core_internal.def b/bin/scripts/__core_internal.def index 3c477da..e890ae4 100644 --- a/bin/scripts/__core_internal.def +++ b/bin/scripts/__core_internal.def @@ -39,6 +39,7 @@ LOGDETAIL * Dangerous variables removed. //----------------------------------------------- // Load all conf files from directory /conf/ // get all *.conf file names from /conf/ directory, store the names in list 'fl' and the amount in 'fcount' +LOG ** Configuring PseuWoW... SET,fcount ?{LGETFILES,fl,conf conf} // sort the list, load conf files alphabetically. LSORT fl @@ -76,9 +77,14 @@ APPLYPERMISSIONS // remove dangerous variables CLEANUPVARS +// set permissions for internal functions +INTERNAL_PERM + // if its not set in the conf file, default it to "." (WoWEmu & MaNGOS style) DEFAULT,#CMDCHAR . +LOG ** All Config done. + //-------------------------------------------------- #script=internal_perm diff --git a/bin/scripts/__core_list_extensions.def b/bin/scripts/__core_list_extensions.def index 42de5d8..33d52a9 100644 --- a/bin/scripts/__core_list_extensions.def +++ b/bin/scripts/__core_list_extensions.def @@ -2,7 +2,6 @@ //-------------------------------------------- #script=lcontains -#permission=255 //-------------------------------------------- // return true if any list element matches @def, else return false. // @0: list name, @def: search string @@ -11,23 +10,22 @@ set,i 0 set,l ?{globname ${@0}} out list: ${l} - len: ?{llen ${l}} - + if ?{not ?{llen ${l}}} - return + return endif set,result false loop - out eq:?{equal,${i} ?{llen ${l}}} i:${i} len:?{llen ${l}} - if ?{equal,${i} ?{llen ${l}}} - exitloop - endif - set,elem ?{lindex,{${l}} ${i}} - if ?{equal,{${elem}} ${@def}} - set,result true - exitloop - endif - add,i 1 + if ?{equal,${i} ?{llen ${l}}} + exitloop + endif + set,elem ?{lindex,{${l}} ${i}} + if ?{equal,{${elem}} ${@def}} + set,result true + exitloop + endif + add,i 1 endloop unset i unset l diff --git a/bin/scripts/__core_wrappers.def b/bin/scripts/__core_wrappers.def index 0b2a4d7..c3da773 100644 --- a/bin/scripts/__core_wrappers.def +++ b/bin/scripts/__core_wrappers.def @@ -2,6 +2,7 @@ //------------------------------------------------ #script=gc +#permission=0 //------------------------------------------------ // example script to write into channel "generalchat" // usage: "gc bla bla..." diff --git a/bin/scripts/_nopermission.def b/bin/scripts/_nopermission.def index aeca5bf..5549556 100644 --- a/bin/scripts/_nopermission.def +++ b/bin/scripts/_nopermission.def @@ -1,6 +1,4 @@ -#permission=255 - -// GETS EXECUTED IF A PLAYER TRIES TO GIVE PSEUWOW A COMMAND AND IS NOT ALLOWED TO +// this script gets executed if a player tries to give pseuwow a command but is not allowed to // Arguments: // ========== diff --git a/bin/scripts/_onwhisper.def b/bin/scripts/_onwhisper.def index 7f6d512..ba68371 100644 --- a/bin/scripts/_onwhisper.def +++ b/bin/scripts/_onwhisper.def @@ -1,5 +1,3 @@ -#permission=255 - // EXECUTED EVERYTIME A WHISPER IS BEEING RECIEVED // comment out the following line if you dont need it diff --git a/src/Client/Cli.cpp b/src/Client/Cli.cpp index 378ef53..f475883 100644 --- a/src/Client/Cli.cpp +++ b/src/Client/Cli.cpp @@ -22,26 +22,21 @@ void CliRunnable::run(void) if (in == NULL) return; for(int i=0;in[i];i++) - if(in[i]=='\r'||in[i]=='\n') - { - in[i]=0; - break; - } + if(in[i]=='\r'||in[i]=='\n') + { + in[i]=0; + break; + } if(in[0]==0) continue; if(in[0]=='!') cur = &in[1]; else { - try - { - out = cur.empty() ? in : (cur+" "+in); - _instance->GetScripts()->RunSingleLine(out); - } - catch (...) - { - printf("Exception while executing CLI command!\n"); - } + out = cur.empty() ? in : (cur+" "+in); + _instance->AddCliCommand(out); + // add delay just if necessary + //ZThread::Thread::sleep(50); } } } diff --git a/src/Client/DefScript/VarSet.cpp b/src/Client/DefScript/VarSet.cpp index f77d2b9..3c6ed4d 100644 --- a/src/Client/DefScript/VarSet.cpp +++ b/src/Client/DefScript/VarSet.cpp @@ -146,7 +146,7 @@ bool VarSet::ReadVarsFromFile(std::string fn) unsigned int pos=line.find("="); if(pos!=std::string::npos) { - std::string v=line.substr(0,pos);; + std::string v=line.substr(0,pos); if(upper) v=toUpper(v); diff --git a/src/Client/DefScriptInterface.cpp b/src/Client/DefScriptInterface.cpp index d08f8d3..a5d3ee3 100644 --- a/src/Client/DefScriptInterface.cpp +++ b/src/Client/DefScriptInterface.cpp @@ -94,7 +94,7 @@ DefReturnResult DefScriptPackage::SCsavecache(CmdSet& Set){ str << ((PseuInstance*)parentMethod)->GetWSession()->objmgr.GetItemProtoCount(); str << " Item Prototypes"; str << " ]"; - + ((PseuInstance*)parentMethod)->GetWSession()->SendChatMessage(CHAT_MSG_SAY,0,str.str(),""); } return true; @@ -135,7 +135,7 @@ DefReturnResult DefScriptPackage::SCemote(CmdSet& Set){ DefReturnResult DefScriptPackage::SCfollow(CmdSet& Set) { DEF_RETURN_ERROR; // prevent execution for now - /* + /* WorldSession *ws=((PseuInstance*)parentMethod)->GetWSession(); if(Set.defaultarg.empty()){ ws->SendChatMessage(CHAT_MSG_SAY,0,"Stopping! (Please give me a Playername to follow!)",""); @@ -149,7 +149,7 @@ DefReturnResult DefScriptPackage::SCfollow(CmdSet& Set) else ss << "Can't follow player '"<SendChatMessage(CHAT_MSG_SAY,0,ss.str(),""); - */ + */ return true; } @@ -228,23 +228,23 @@ DefReturnResult DefScriptPackage::SClogerror(CmdSet& Set){ DefReturnResult DefScriptPackage::SCcastspell(CmdSet& Set) { - if(Set.defaultarg.empty()) - return false; - if(!(((PseuInstance*)parentMethod)->GetWSession())) - { - logerror("Invalid Script call: SCcastspell: WorldSession not valid"); - DEF_RETURN_ERROR; - } + if(Set.defaultarg.empty()) + return false; + if(!(((PseuInstance*)parentMethod)->GetWSession())) + { + logerror("Invalid Script call: SCcastspell: WorldSession not valid"); + DEF_RETURN_ERROR; + } - uint32 spellId = atoi(Set.defaultarg.c_str()); + uint32 spellId = atoi(Set.defaultarg.c_str()); - if (spellId <= 0) - { - return false; - } + if (spellId <= 0) + { + return false; + } - ((PseuInstance*)parentMethod)->GetWSession()->SendCastSpell(spellId); - return true; + ((PseuInstance*)parentMethod)->GetWSession()->SendCastSpell(spellId); + return true; } DefReturnResult DefScriptPackage::SCqueryitem(CmdSet& Set){ @@ -297,22 +297,32 @@ DefReturnResult DefScriptPackage::SCtarget(CmdSet& Set) DefReturnResult DefScriptPackage::SCloadscp(CmdSet& Set) { - DefReturnResult r; - if(Set.arg[0].empty() || Set.defaultarg.empty()) + SCPDatabaseMgr& dbmgr = ((PseuInstance*)parentMethod)->dbmgr; + if(Set.defaultarg.empty()) // exit if no filename was given return false; std::string dbname = stringToLower(Set.arg[0]); - // TODO: remove db if loading was not successful - uint32 sections=((PseuInstance*)parentMethod)->dbmgr.GetDB(dbname).LoadFromFile((char*)Set.defaultarg.c_str()); - if(sections) + uint32 sections = 0; + if(dbname.empty()) // if no db name was supplied, try to find it automatically in the file ("#dbname=...") { - logdetail("Loaded SCP: \"%s\" [%s] (%u sections)",dbname.c_str(),Set.defaultarg.c_str(),sections); + sections = dbmgr.AutoLoadFile((char*)Set.defaultarg.c_str()); + if(!sections) + { + logerror("Tried to auto-load SCP file: \"%s\", but no name tag found. skipped."); + } } else { - logerror("Failed to load SCP: \"%s\" [%s]",dbname.c_str(),Set.defaultarg.c_str()); + sections = dbmgr.GetDB(dbname).LoadFromFile((char*)Set.defaultarg.c_str()); + if(sections) + { + logdetail("Loaded SCP: \"%s\" [%s] (%u sections)",dbname.c_str(),Set.defaultarg.c_str(),sections); + } + else + { + logerror("Failed to load SCP: \"%s\" [%s]",dbname.c_str(),Set.defaultarg.c_str()); + } } - r.ret=toString((uint64)sections); - return r; + return toString((uint64)sections);; } DefReturnResult DefScriptPackage::SCScpExists(CmdSet& Set) @@ -519,10 +529,10 @@ DefReturnResult DefScriptPackage::SCGetItemProtoValue(CmdSet& Set) uint32 tmp=0; if(t=="class") r.ret=toString(proto->Class); else if(t=="subclass") r.ret=toString(proto->SubClass); - else if(t=="name1" || t=="name") proto->Name[0]; - else if(t=="name2") proto->Name[1]; - else if(t=="name3") proto->Name[2]; - else if(t=="name4") proto->Name[3]; + else if(t=="name1" || t=="name") r.ret=proto->Name[0]; + else if(t=="name2") r.ret=proto->Name[1]; + else if(t=="name3") r.ret=proto->Name[2]; + else if(t=="name4") r.ret=proto->Name[3]; else if(t=="model" || t=="displayid") r.ret=toString(proto->DisplayInfoID); else if(t=="quality") r.ret=toString(proto->Quality); else if(t=="flags") r.ret=toString(proto->Flags); @@ -756,7 +766,7 @@ void DefScriptPackage::My_LoadUserPermissions(VarSet &vs) { sub = variables[i].name.substr(0,strlen(prefix)); if(sub == prefix) - { + { usr = variables[i].name.substr(strlen(prefix), variables[i].name.length() - strlen(prefix)); my_usrPermissionMap[usr] = atoi(variables[i].value.c_str()); DEBUG( logdebug("Player '%s' permission = %u",usr.c_str(),atoi(variables[i].value.c_str())); ) @@ -766,7 +776,7 @@ void DefScriptPackage::My_LoadUserPermissions(VarSet &vs) void DefScriptPackage::My_Run(std::string line, std::string username) { - uint8 scperm=255; // builtin functions that have no explicit req. permission level assigned should be secure from beeing called + int16 scperm = -1; // builtin functions that have no explicit req. permission level assigned should be secure from beeing called from ingame uint8 usrperm=0; // users/players that have no explicit permission assigned should have minimal permission for (std::map::iterator i = my_usrPermissionMap.begin(); i != my_usrPermissionMap.end(); i++) @@ -778,16 +788,15 @@ void DefScriptPackage::My_Run(std::string line, std::string username) } DefXChgResult final; - if(usrperm < 255) + if(usrperm < 255 && line.find("?{")!=std::string::npos) { - if(line.find("?{")!=std::string::npos) - logerror("WARNING: %s wanted to exec \"%s\"",username.c_str(),line.c_str()); + logerror("WARNING: %s wanted to exec \"%s\"",username.c_str(),line.c_str()); final=ReplaceVars(line,NULL,0,false); // prevent execution of embedded scripts (= using return values) that could trigger dangerous stuff. } else final=ReplaceVars(line,NULL,0,true); // exec as usual - + CmdSet curSet; SplitLine(curSet,final.str); @@ -799,17 +808,22 @@ void DefScriptPackage::My_Run(std::string line, std::string username) } } - if(usrperm < scperm) + + if(scperm > 0) // skip "invisible" scripts (without any permission set) completely. { - CmdSet Set; - Set.arg[0] = username; - Set.arg[1] = toString(usrperm); - Set.arg[2] = toString(scperm); - Set.arg[3] = curSet.cmd; - RunScript("_nopermission",&Set); - return; + if(usrperm < scperm) + { + CmdSet Set; + Set.arg[0] = username; + Set.arg[1] = toString(usrperm); + Set.arg[2] = toString(scperm); + Set.arg[3] = curSet.cmd; + RunScript("_nopermission",&Set); + return; + } } + Interpret(curSet); } diff --git a/src/Client/GUI/DrawObjMgr.cpp b/src/Client/GUI/DrawObjMgr.cpp new file mode 100644 index 0000000..8490c7d --- /dev/null +++ b/src/Client/GUI/DrawObjMgr.cpp @@ -0,0 +1,67 @@ +#include "common.h" +#include "log.h" +#include "DrawObject.h" +#include "DrawObjMgr.h" + +DrawObjMgr::DrawObjMgr() +{ + DEBUG( logdebug("DrawObjMgr created") ); +} + +DrawObjMgr::~DrawObjMgr() +{ + DEBUG( logdebug("~DrawObjMgr(), deleting %u DrawObjects...", _storage.size() ) ); + for(DrawObjStorage::iterator i = _storage.begin(); i != _storage.end(); i++) + { + DEBUG( logdebug("del for guid "I64FMT, i->first) ); + delete i->second; // this can be done safely, since the object ptrs are not accessed + } +} + +void DrawObjMgr::Add(uint64 objguid, DrawObject *o) +{ + _add.add(std::pair(objguid,o)); +} + +void DrawObjMgr::Delete(uint64 guid) +{ + _del.add(guid); +} + +void DrawObjMgr::Update(void) +{ + ZThread::FastMutex mut; + + // now for the threadsafe part: lock every thread except this one + // to prevent obj ptr corruption caused by other running threads + // TODO: lock only main thread (that should be the only one to delete objects anyway!) + mut.acquire(); + + // add objects waiting on the add queue to the real storage + while(_add.size()) + { + std::pair p = _add.next(); + _storage[p.first] = p.second; + } + + // same for objects that should be deleted + while(_del.size()) + { + uint64 guid = _del.next(); + if(_storage.find(guid) != _storage.end()) + { + DrawObject *o = _storage[guid]; + _storage.erase(guid); + delete o; + } + } + + // now draw everything + for(DrawObjStorage::iterator i = _storage.begin(); i != _storage.end(); i++) + { + i->second->Draw(); + } + + mut.release(); + +} diff --git a/src/Client/GUI/DrawObjMgr.h b/src/Client/GUI/DrawObjMgr.h new file mode 100644 index 0000000..2ae9182 --- /dev/null +++ b/src/Client/GUI/DrawObjMgr.h @@ -0,0 +1,27 @@ +#ifndef DRAWOBJMGR_H +#define DRAWOBJMGR_H + +#include + +class DrawObject; + +typedef std::map DrawObjStorage; + +class DrawObjMgr +{ +public: + DrawObjMgr(); + ~DrawObjMgr(); + void Add(uint64,DrawObject*); + void Delete(uint64); + void Update(void); // Threadsafe! delete code must be called from here! + uint32 StorageSize(void) { return _storage.size(); } + +private: + DrawObjStorage _storage; + ZThread::LockedQueue _del; + ZThread::LockedQueue,ZThread::FastMutex > _add; + +}; + +#endif diff --git a/src/Client/GUI/DrawObject.cpp b/src/Client/GUI/DrawObject.cpp new file mode 100644 index 0000000..13107a8 --- /dev/null +++ b/src/Client/GUI/DrawObject.cpp @@ -0,0 +1,21 @@ +#include "common.h" +#include "PseuGui.h" +#include "DrawObject.h" +#include "PseuWoW.h" + +DrawObject::DrawObject(irr::scene::ISceneManager *smgr, Object *obj) +{ + _smgr = smgr; + _obj = obj; + DEBUG( logdebug("create DrawObject() this=%X obj=%X smgr=%X",this,_obj,_smgr) ); +} + +DrawObject::~DrawObject() +{ + DEBUG( logdebug("~DrawObject() this=%X obj=%X smgr=%X",this,_obj,_smgr) ); +} + +void DrawObject::Draw(void) +{ + +} diff --git a/src/Client/GUI/DrawObject.h b/src/Client/GUI/DrawObject.h new file mode 100644 index 0000000..d2f2cbd --- /dev/null +++ b/src/Client/GUI/DrawObject.h @@ -0,0 +1,23 @@ +#ifndef DRAWOBJECT_H +#define DRAWOBJECT_H + +#include "common.h" +#include "irrlicht/irrlicht.h" + +class Object; + +class DrawObject +{ +public: + DrawObject(irr::scene::ISceneManager*, Object*); + ~DrawObject(); + void Draw(void); // call only in threadsafe environment!! (ensure the obj ptr is still valid!) + // additionally, we dont use a GetObject() func - that would fuck things up if the object was already deleted. + +private: + Object *_obj; + irr::scene::ISceneManager *_smgr; + +}; + +#endif diff --git a/src/Client/GUI/PseuGUI.cpp b/src/Client/GUI/PseuGUI.cpp index 353b7c3..0af09ce 100644 --- a/src/Client/GUI/PseuGUI.cpp +++ b/src/Client/GUI/PseuGUI.cpp @@ -1,5 +1,7 @@ #include "common.h" #include "irrlicht/irrlicht.h" +#include "Object.h" +#include "DrawObject.h" #include "PseuWoW.h" #include "PseuGUI.h" @@ -55,115 +57,145 @@ PseuGUI::PseuGUI() PseuGUI::~PseuGUI() { - this->Shutdown(); -} - -void PseuGUI::SetInstance(PseuInstance *i) -{ - _instance = i; + this->Cancel(); + _instance->DeleteGUI(); // this makes the instance set its gui ptr to NULL } void PseuGUI::SetDriver(uint8 driverId) { - switch(driverId) - { - case DIRECTX9: _driverType = video::EDT_DIRECT3D9;break; - case DIRECTX8: _driverType = video::EDT_DIRECT3D8;break; - case OPENGL: _driverType = video::EDT_OPENGL; break; - case SOFTWARE: _driverType = video::EDT_SOFTWARE; break; - case BURNINGSVIDEO: _driverType = video::EDT_BURNINGSVIDEO;break; - case NULLDEVICE: _driverType = video::EDT_NULL; break; - default: _driverType = video::EDT_BURNINGSVIDEO; // if no valid driver detected, use software - } - - // TODO: add support for changing driver during runtime? -} - -void PseuGUI::SetResolution(uint16 x, uint16 y, uint16 depth) -{ - _xres = x; - _yres = y; - _colordepth = depth; -} - -void PseuGUI::SetWindowed(bool b) -{ - _windowed = b; - // see PseuGUI::Init(): !_windowed == fullscreen -} - -void PseuGUI::SetVSync(bool b) -{ - _vsync = b; -} - -void PseuGUI::UseShadows(bool b) -{ - _shadows = b; -} - -// if this fuction is called from another thread the device will not work correctly. o_O -void PseuGUI::_Init(void) -{ - _device = createDevice(_driverType,dimension2d(_xres,_yres),_colordepth,!_windowed,_shadows,_vsync); - DEBUG(logdebug("PseuGUI::Init() _device=%X",_device)); - _device->setWindowCaption(L"PseuWoW - Initializing"); - _driver = _device->getVideoDriver(); - _smgr = _device->getSceneManager(); - //... - _initialized = true; -} - -void PseuGUI::Shutdown(void) -{ - DEBUG(logdebug("PseuGUI::Shutdown()")); - _mustdie = true; - if(_device) - { - _device->drop(); - _device = NULL; - } -} - -void PseuGUI::Run(void) -{ - if(!_initialized) - this->_Init(); - - DEBUG(logdebug("PseuGUI::Run() _device=%X",_device)); - - int lastFPS = -1, fps = -1; - - while(_device && _device->run() && !_mustdie) - { - if (!_device->isWindowActive()) - { - _device->sleep(10); // save cpu & gpu power if not focused - } - _driver->beginScene(true, true, 0); - - _smgr->drawAll(); - - _driver->endScene(); - - fps = _driver->getFPS(); - - if (lastFPS != fps) - { - core::stringw str = L"PseuWoW ["; - str += _driver->getName(); - str += "] FPS:"; - str += fps; - - _device->setWindowCaption(str.c_str()); - - lastFPS = fps; - DEBUG(logdebug("PseuGUI: Current FPS: %u",fps)); - } - - } - DEBUG(logdebug("PseuGUI::Run() finished")); - Shutdown(); -} - - + switch(driverId) + { + case DIRECTX9: _driverType = video::EDT_DIRECT3D9;break; + case DIRECTX8: _driverType = video::EDT_DIRECT3D8;break; + case OPENGL: _driverType = video::EDT_OPENGL; break; + case SOFTWARE: _driverType = video::EDT_SOFTWARE; break; + case BURNINGSVIDEO: _driverType = video::EDT_BURNINGSVIDEO;break; + case NULLDEVICE: _driverType = video::EDT_NULL; break; + default: _driverType = video::EDT_BURNINGSVIDEO; // if no valid driver detected, use software + } + + // TODO: add support for changing driver during runtime? +} + +void PseuGUI::SetResolution(uint16 x, uint16 y, uint16 depth) +{ + _xres = x; + _yres = y; + _colordepth = depth; +} + +void PseuGUI::SetWindowed(bool b) +{ + _windowed = b; + // see PseuGUI::Init(): !_windowed == fullscreen +} + +void PseuGUI::SetVSync(bool b) +{ + _vsync = b; +} + +void PseuGUI::UseShadows(bool b) +{ + _shadows = b; +} + +// if this fuction is called from another thread the device will not work correctly. o_O +void PseuGUI::_Init(void) +{ + _device = createDevice(_driverType,dimension2d(_xres,_yres),_colordepth,!_windowed,_shadows,_vsync); + DEBUG(logdebug("PseuGUI::Init() _device=%X",_device)); + _device->setWindowCaption(L"PseuWoW - Initializing"); + _driver = _device->getVideoDriver(); + _smgr = _device->getSceneManager(); + //... + _initialized = true; +} + +void PseuGUI::Cancel(void) +{ + DEBUG(logdebug("PseuGUI::Cancel()")); + _mustdie = true; + if(_device) + { + _device->drop(); + _device = NULL; + } +} + +void PseuGUI::Shutdown(void) +{ + DEBUG(logdebug("PseuGUI::Shutdown()")); + _mustdie = true; +} + +void PseuGUI::Run(void) +{ + if(!_initialized) + this->_Init(); + + DEBUG(logdebug("PseuGUI::Run() _device=%X",_device)); + + int lastFPS = -1, fps = -1; + + while(_device && _device->run() && !_mustdie) + { + if (!_device->isWindowActive()) + { + _device->sleep(10); // save cpu & gpu power if not focused + } + + try + { + _driver->beginScene(true, true, 0); + + domgr.Update(); // iterate over DrawObjects, draw them and clean up + + _smgr->drawAll(); + + _driver->endScene(); + } + catch(...) + { + logerror("Unhandled exception in PseuGUI::Run() device=%X smgr=%X objects:%u", _device, _smgr, domgr.StorageSize()); + } + + fps = _driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"PseuWoW ["; + str += _driver->getName(); + str += "] FPS:"; + str += fps; + + _device->setWindowCaption(str.c_str()); + + lastFPS = fps; + DEBUG(logdebug("PseuGUI: Current FPS: %u",fps)); + } + + } + DEBUG(logdebug("PseuGUI::Run() finished")); + Cancel(); // already got shut down somehow, we can now safely cancel and drop the device +} + +// called from ObjMgr::Remove(guid) +void PseuGUI::NotifyObjectDeletion(uint64 guid) +{ + domgr.Delete(guid); +} + +// called from ObjMgr::Add(Object*) +void PseuGUI::NotifyObjectCreation(Object *o) +{ + DrawObject *d = new DrawObject(_smgr,o); + domgr.Add(o->GetGUID(),d); +} + +void PseuGUI::SetInstance(PseuInstance* in) +{ + _instance = in; +} + + diff --git a/src/Client/GUI/PseuGUI.h b/src/Client/GUI/PseuGUI.h index 69533f5..801d457 100644 --- a/src/Client/GUI/PseuGUI.h +++ b/src/Client/GUI/PseuGUI.h @@ -2,11 +2,12 @@ #define PSEUGUI_H #include "irrlicht/irrlicht.h" +#include "DrawObjMgr.h" class PseuGUI; +class Object; class PseuInstance; - class PseuGUIRunnable : public ZThread::Runnable { public: @@ -25,26 +26,33 @@ public: PseuGUI(); ~PseuGUI(); - void Run(void); void SetInstance(PseuInstance*); + void Run(void); void SetDriver(uint8); void SetResolution(uint16 x, uint16 y, uint16 depth=32); void SetWindowed(bool); void SetVSync(bool); void UseShadows(bool); + void Cancel(void); void Shutdown(void); + inline bool MustDie(void) { return _mustdie; } + + // interfaces to tell the gui what to draw + void NotifyObjectDeletion(uint64 guid); + void NotifyObjectCreation(Object *o); private: void _Init(void); uint16 _xres,_yres,_colordepth; bool _windowed,_vsync,_shadows; bool _initialized,_mustdie; - PseuInstance *_instance; irr::IrrlichtDevice *_device; irr::video::IVideoDriver* _driver; irr::scene::ISceneManager* _smgr; irr::gui::IGUIEnvironment* _guienv; irr::video::E_DRIVER_TYPE _driverType; + DrawObjMgr domgr; + PseuInstance *_instance; }; diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp index eab904e..3b4e10c 100644 --- a/src/Client/PseuWoW.cpp +++ b/src/Client/PseuWoW.cpp @@ -25,15 +25,15 @@ PseuInstanceRunnable::PseuInstanceRunnable() void PseuInstanceRunnable::run(void) { _i = new PseuInstance(this); - _i->SetConfDir("./conf/"); + _i->SetConfDir("./conf/"); _i->SetScpDir("./scripts/"); - if(_i->Init()) + if(_i->Init()) { - _i->Run(); + _i->Run(); } else { - getchar(); + getchar(); // if init failed, wait for keypress before exit } delete _i; } @@ -54,6 +54,8 @@ PseuInstance::PseuInstance(PseuInstanceRunnable *run) _conf=NULL; _cli=NULL; _rmcontrol=NULL; + _gui=NULL; + _guithread=NULL; _stop=false; _fastquit=false; _startrealm=true; @@ -61,7 +63,6 @@ PseuInstance::PseuInstance(PseuInstanceRunnable *run) _error=false; _initialized=false; - } PseuInstance::~PseuInstance() @@ -72,6 +73,11 @@ PseuInstance::~PseuInstance() // delete _cli; // ok this is a little mem leak... can be fixed sometime in future } + if(_gui) + _gui->Shutdown(); + if(_guithread) + _guithread->wait(); + if(_rmcontrol) delete _rmcontrol; if(_rsession) @@ -94,14 +100,14 @@ bool PseuInstance::Init(void) { if(_confdir.empty()) _confdir="./conf/"; if(_scpdir.empty()) - _scpdir="./scp/"; + _scpdir="./scripts/"; - srand((unsigned)time(NULL)); - RAND_set_rand_method(RAND_SSLeay()); // init openssl randomizer - - _scp=new DefScriptPackage(); + srand((unsigned)time(NULL)); + RAND_set_rand_method(RAND_SSLeay()); // init openssl randomizer + + _scp=new DefScriptPackage(); _scp->SetParentMethod((void*)this); - _conf=new PseuInstanceConf(); + _conf=new PseuInstanceConf(); _scp->SetPath(_scpdir); @@ -138,13 +144,13 @@ bool PseuInstance::Init(void) { if(x>0 && y>0 && (depth==16 || depth==32) && driver>0 && driver<=5) { PseuGUIRunnable *rgui = new PseuGUIRunnable(); - PseuGUI *gui = rgui->GetGUI(); - gui->SetInstance(this); - gui->SetDriver(driver); - gui->SetResolution(x,y,depth); - gui->SetVSync(vsync); - gui->UseShadows(shadows); - ZThread::Thread *t = new ZThread::Thread(rgui); + _gui = rgui->GetGUI(); + _gui->SetInstance(this); + _gui->SetDriver(driver); + _gui->SetResolution(x,y,depth); + _gui->SetVSync(vsync); + _gui->UseShadows(shadows); + _guithread = new ZThread::Thread(rgui); } else logerror("GUI: incorrect settings!"); @@ -164,13 +170,13 @@ bool PseuInstance::Init(void) { if(_error) { - logcritical("Errors while initializing!"); + logcritical("Errors while initializing!"); return false; } log("Init complete.\n"); - _initialized=true; - return true; + _initialized=true; + return true; } void PseuInstance::Run(void) @@ -232,6 +238,10 @@ void PseuInstance::Run(void) void PseuInstance::Update() { + // if the user typed anything into the console, process it before anything else + if(_cli) // need to to process only if cli exists + ProcessCliQueue(); + // delete sessions if they are no longer needed if(_rsession && _rsession->MustDie()) { @@ -264,7 +274,7 @@ void PseuInstance::Update() _rsession->Connect(); _rsession->SendLogonChallenge(); // and login again } - + // update currently existing/active sessions if(_rsession) _rsession->Update(); @@ -274,7 +284,7 @@ void PseuInstance::Update() logerror("Unhandled exception in WorldSession::Update()"); } - + if(_rmcontrol) { _rmcontrol->Update(); @@ -290,6 +300,28 @@ void PseuInstance::Update() this->Sleep(GetConf()->networksleeptime); } +void PseuInstance::ProcessCliQueue(void) +{ + std::string cmd; + while(_cliQueue.size()) + { + cmd = _cliQueue.next(); + try + { + GetScripts()->RunSingleLine(cmd); + } + catch(...) + { + logerror("Exception while executing CLI command: \"%s\"",cmd.c_str()); + } + } +} + +void PseuInstance::AddCliCommand(std::string cmd) +{ + _cliQueue.add(cmd); +} + void PseuInstance::SaveAllCache(void) { //... @@ -306,6 +338,12 @@ void PseuInstance::Sleep(uint32 msecs) GetRunnable()->sleep(msecs); } +void PseuInstance::DeleteGUI(void) +{ + _gui = NULL; + _guithread = NULL; +} + PseuInstanceConf::PseuInstanceConf() { enablecli=false; @@ -317,22 +355,22 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v) { debug=atoi(v.Get("DEBUG").c_str()); realmlist=v.Get("REALMLIST"); - accname=v.Get("ACCNAME"); - accpass=v.Get("ACCPASS"); - exitonerror=(bool)atoi(v.Get("EXITONERROR").c_str()); + accname=v.Get("ACCNAME"); + accpass=v.Get("ACCPASS"); + exitonerror=(bool)atoi(v.Get("EXITONERROR").c_str()); reconnect=atoi(v.Get("RECONNECT").c_str()); - realmport=atoi(v.Get("REALMPORT").c_str()); + realmport=atoi(v.Get("REALMPORT").c_str()); clientversion_string=v.Get("CLIENTVERSION"); - clientbuild=atoi(v.Get("CLIENTBUILD").c_str()); - clientlang=v.Get("CLIENTLANGUAGE"); - realmname=v.Get("REALMNAME"); - charname=v.Get("CHARNAME"); - networksleeptime=atoi(v.Get("NETWORKSLEEPTIME").c_str()); + clientbuild=atoi(v.Get("CLIENTBUILD").c_str()); + clientlang=v.Get("CLIENTLANGUAGE"); + realmname=v.Get("REALMNAME"); + charname=v.Get("CHARNAME"); + networksleeptime=atoi(v.Get("NETWORKSLEEPTIME").c_str()); showopcodes=atoi(v.Get("SHOWOPCODES").c_str()); - hidefreqopcodes=(bool)atoi(v.Get("HIDEFREQOPCODES").c_str()); + hidefreqopcodes=(bool)atoi(v.Get("HIDEFREQOPCODES").c_str()); enablecli=(bool)atoi(v.Get("ENABLECLI").c_str()); allowgamecmd=(bool)atoi(v.Get("ALLOWGAMECMD").c_str()); - enablechatai=(bool)atoi(v.Get("ENABLECHATAI").c_str()); + enablechatai=(bool)atoi(v.Get("ENABLECHATAI").c_str()); notifyping=(bool)atoi(v.Get("NOTIFYPING").c_str()); showmyopcodes=(bool)atoi(v.Get("SHOWMYOPCODES").c_str()); disablespellcheck=(bool)atoi(v.Get("DISABLESPELLCHECK").c_str()); @@ -367,9 +405,9 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v) PseuInstanceConf::~PseuInstanceConf() { - //... + //... } - + diff --git a/src/Client/PseuWoW.h b/src/Client/PseuWoW.h index 346c605..c20d3db 100644 --- a/src/Client/PseuWoW.h +++ b/src/Client/PseuWoW.h @@ -9,6 +9,7 @@ #include "DefScript/DefScript.h" #include "Network/SocketHandler.h" #include "SCPDatabase.h" +#include "GUI/PseuGUI.h" class RealmSession; class WorldSession; @@ -19,34 +20,34 @@ class RemoteController; class PseuInstanceConf { - public: - - PseuInstanceConf(); - ~PseuInstanceConf(); - void ApplyFromVarSet(VarSet &v); - - - uint8 debug; - std::string realmlist; - std::string accname; - std::string accpass; - bool exitonerror; + public: + + PseuInstanceConf(); + ~PseuInstanceConf(); + void ApplyFromVarSet(VarSet &v); + + + uint8 debug; + std::string realmlist; + std::string accname; + std::string accpass; + bool exitonerror; uint32 reconnect; - uint16 realmport; + uint16 realmport; uint16 worldport; - uint8 clientversion[3]; + uint8 clientversion[3]; std::string clientversion_string; - uint16 clientbuild; - std::string clientlang; - std::string realmname; - std::string charname; + uint16 clientbuild; + std::string clientlang; + std::string realmname; + std::string charname; std::string worldhost; - uint16 networksleeptime; + uint16 networksleeptime; uint8 showopcodes; - bool hidefreqopcodes; + bool hidefreqopcodes; bool allowgamecmd; bool enablecli; - bool enablechatai; + bool enablechatai; bool notifyping; bool showmyopcodes; bool disablespellcheck; @@ -57,63 +58,72 @@ class PseuInstanceConf // gui related bool enablegui; // need more here - - + + }; - + class PseuInstance { - public: +public: - PseuInstance(PseuInstanceRunnable *run); - ~PseuInstance(); - + PseuInstance(PseuInstanceRunnable *run); + ~PseuInstance(); - WorldSession *GetWSession(void) { return _wsession; } - RealmSession *GetRSession(void) { return _rsession; } - PseuInstanceConf *GetConf(void) { return _conf; } - DefScriptPackage *GetScripts(void) { return _scp; } - PseuInstanceRunnable *GetRunnable(void) { return _runnable; } - void SetConfDir(std::string dir) { _confdir = dir; } - std::string GetConfDir(void) { return _confdir; } - void SetScpDir(std::string dir) { _scpdir = dir; } - void SetSessionKey(BigNumber key) { _sessionkey = key; } - BigNumber GetSessionKey(void) { return _sessionkey; } - void SetError(void) { _error = true; } + + inline WorldSession *GetWSession(void) { return _wsession; } + inline RealmSession *GetRSession(void) { return _rsession; } + inline PseuInstanceConf *GetConf(void) { return _conf; } + inline DefScriptPackage *GetScripts(void) { return _scp; } + inline PseuInstanceRunnable *GetRunnable(void) { return _runnable; } + inline PseuGUI *GetGUI(void) { return _gui; } + void DeleteGUI(void); + + inline void SetConfDir(std::string dir) { _confdir = dir; } + inline std::string GetConfDir(void) { return _confdir; } + inline void SetScpDir(std::string dir) { _scpdir = dir; } + inline void SetSessionKey(BigNumber key) { _sessionkey = key; } + inline BigNumber GetSessionKey(void) { return _sessionkey; } + inline void SetError(void) { _error = true; } SCPDatabaseMgr dbmgr; - - bool Init(); - void SaveAllCache(void); - void Stop(void) { _stop = true; } - bool Stopped(void) { return _stop; } - void SetFastQuit(bool q=true) { _fastquit=true; } - void Quit(void); - void Run(void); - void Update(void); - void Sleep(uint32 msecs); - - void CreateWorldSession(void) { _createws = true; } - private: + bool Init(); + void SaveAllCache(void); + inline void Stop(void) { _stop = true; } + inline bool Stopped(void) { return _stop; } + inline void SetFastQuit(bool q=true) { _fastquit=true; } + void Quit(void); + void Run(void); + void Update(void); + void Sleep(uint32 msecs); + + inline void CreateWorldSession(void) { _createws = true; } + + void ProcessCliQueue(void); + void AddCliCommand(std::string); + +private: PseuInstanceRunnable *_runnable; - RealmSession *_rsession; - WorldSession *_wsession; - PseuInstanceConf *_conf; - DefScriptPackage *_scp; - std::string _confdir,_scpdir; - bool _initialized; - bool _stop,_fastquit; + RealmSession *_rsession; + WorldSession *_wsession; + PseuInstanceConf *_conf; + DefScriptPackage *_scp; + std::string _confdir,_scpdir; // _scpdir is the scipts dir, and NOT where SCP files are stored!! + bool _initialized; + bool _stop,_fastquit; bool _startrealm; bool _error; bool _createws; - BigNumber _sessionkey; + BigNumber _sessionkey; char *_ver,*_ver_short; SocketHandler _sh; CliRunnable *_cli; ZThread::Thread _clithread; RemoteController *_rmcontrol; + ZThread::LockedQueue _cliQueue; + PseuGUI *_gui; + ZThread::Thread *_guithread; }; @@ -123,11 +133,11 @@ public: PseuInstanceRunnable(); void run(void); void sleep(uint32); - PseuInstance *GetInstance(void) { return _i; } + inline PseuInstance *GetInstance(void) { return _i; } private: PseuInstance *_i; }; -#endif \ No newline at end of file +#endif diff --git a/src/Client/SCPDatabase.cpp b/src/Client/SCPDatabase.cpp index 420d7db..709ba53 100644 --- a/src/Client/SCPDatabase.cpp +++ b/src/Client/SCPDatabase.cpp @@ -2,30 +2,48 @@ #include "common.h" #include "SCPDatabase.h" + uint32 SCPDatabase::LoadFromFile(char *fn) { std::fstream fh; - std::string line,value,entry,storage; - uint32 id=0,sections=0; - char c; + uint32 size = GetFileSize(fn); + if(!size) + return 0; - fh.open(fn,std::ios_base::in); + fh.open(fn,std::ios_base::in | std::ios_base::binary); if( !fh.is_open() ) return 0; - while(!fh.eof()) + + char *buf = new char[size]; + fh.read(buf,size); + fh.close(); + + uint32 sections = LoadFromMem(buf,size); + delete [] buf; + return sections; +} + + +uint32 SCPDatabase::LoadFromMem(char *buf, uint32 size) +{ + std::string line,value,entry,storage; + uint32 id=0,sections=0; + + for(uint32 pos = 0; pos < size; pos++) { - c=fh.get(); - if(c=='\n' || fh.eof()) + 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[1]=='/')) ) + if(line.empty() || (line.length() > 1 && (line[0]=='#' || (line[0]=='/' && line[1]=='/'))) ) { line.clear(); continue; } + if(line[line.size()-1] == 13) // 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 '[' @@ -45,9 +63,8 @@ uint32 SCPDatabase::LoadFromFile(char *fn) line.clear(); } else - line+=c; // fill up line until a newline is reached (see above) + line += buf[pos]; // fill up line until a newline is reached (see above) } - fh.close(); return sections; } @@ -73,10 +90,7 @@ bool SCPField::HasEntry(std::string e) std::string SCPField::GetString(std::string entry) { //return HasEntry(entry) ? _map[entry] : ""; - if(HasEntry(entry)) - return _map[entry]; - else - return ""; + return _map[entry]; } // note that this can take a while depending on the size of the database! @@ -101,11 +115,64 @@ SCPDatabase& SCPDatabaseMgr::GetDB(std::string n) return _map[n]; } +uint32 SCPDatabaseMgr::AutoLoadFile(char *fn) +{ + 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(); + + std::string line,dbname; + 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[0] == '#') + { + uint32 eq = line.find("="); + if(eq != std::string::npos) + { + 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; + } + } + } + } + else + line += buf[pos]; + } + delete [] buf; + + if(dbname.empty()) + return 0; + + uint32 sections = GetDB(dbname).LoadFromMem(buf,size); + return sections; + +} + // -- helper functions -- // -std::string SCPDatabaseMgr::GetZoneName(uint32 id) +std::string SCPDatabaseMgr::GetAreaName(uint32 id) { - return GetDB("zone").GetField(id).GetString("name"); + return GetDB("area").GetField(id).GetString("name"); } std::string SCPDatabaseMgr::GetRaceName(uint32 id) @@ -140,4 +207,4 @@ std::string SCPDatabaseMgr::GetLangName(uint32 id) //if(r.empty()) // r = LookupName(id,langNames); return r; -} \ No newline at end of file +} diff --git a/src/Client/SCPDatabase.h b/src/Client/SCPDatabase.h index 3df8675..c7da857 100644 --- a/src/Client/SCPDatabase.h +++ b/src/Client/SCPDatabase.h @@ -3,36 +3,82 @@ #include -struct SCPEntry +/* + * Some preparations for compiled databases. i will continue this later. [FG] + +enum SCPTypes { - std::string entry; - std::string value; + SCP_TYPE_STRING = 0, + SCP_TYPE_INT, + SCP_TYPE_UINT, + SCP_TYPE_FLOAT }; +class SCPEntry +{ +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; + } + } +}; + +*/ + typedef std::map SCPEntryMap; class SCPField { public: std::string GetString(std::string); - uint64 GetInteger(std::string entry) { return toInt(GetString(entry)); } - double GetDouble(std::string entry) { return strtod(GetString(entry).c_str(),NULL); } - void Set(std::string entry,std::string value) { _map[entry]=value; } + 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; class SCPDatabase { public: - SCPField& GetField(uint32 id) { return _map[id]; } + 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); private: @@ -47,11 +93,13 @@ class SCPDatabaseMgr public: bool HasDB(std::string); SCPDatabase& GetDB(std::string); + uint32 AutoLoadFile(char *fn); + inline void DropDB(std::string s) { _map.erase(stringToLower(s)); } ////////////////////// // helper functions // ////////////////////// - std::string GetZoneName(uint32 id); + std::string GetAreaName(uint32 id); std::string GetRaceName(uint32 id); std::string GetClassName_(uint32 id); std::string GetGenderName(uint32 id); diff --git a/src/Client/World/ObjMgr.cpp b/src/Client/World/ObjMgr.cpp index 1b86e73..0948a76 100644 --- a/src/Client/World/ObjMgr.cpp +++ b/src/Client/World/ObjMgr.cpp @@ -1,46 +1,66 @@ +#include "common.h" +#include "log.h" +#include "PseuWoW.h" #include "ObjMgr.h" +#include "GUI/PseuGUI.h" + +ObjMgr::ObjMgr() +{ + DEBUG(logdebug("DEBUG: ObjMgr created")); +} ObjMgr::~ObjMgr() { RemoveAll(); } +void ObjMgr::SetInstance(PseuInstance *i) +{ + _instance = i; + DEBUG(logdebug("DEBUG: ObjMgr instance set to 0x%X",i)); +} + void ObjMgr::RemoveAll(void) { for(ItemProtoList::iterator i = _iproto.begin(); i!=_iproto.end(); i++) { delete *i; } - for(ObjectList::iterator i = _obj.begin(); i!=_obj.end(); i++) + while(_obj.size()) { - delete *i; + Remove(_obj.begin()->first); } } void ObjMgr::Remove(uint64 guid) { - for(ObjectList::iterator i = _obj.begin(); i!=_obj.end(); i++) - if((*i)->GetGUID() == guid) - { - delete *i; - _obj.erase(i); - return; - } - + Object *o = GetObj(guid); + if(o) + { + PseuGUI *gui = _instance->GetGUI(); + if(gui) + gui->NotifyObjectDeletion(guid); // we have a gui, which must delete linked DrawObject + _obj.erase(guid); // now delete the obj from the mgr + delete o; // and delete the obj itself + } } void ObjMgr::Add(Object *o) { - _obj.push_back(o); + _obj[o->GetGUID()] = o; + + PseuGUI *gui = _instance->GetGUI(); + if(gui) + gui->NotifyObjectCreation(o); } Object *ObjMgr::GetObj(uint64 guid) { if(!guid) return NULL; - for(ObjectList::iterator i = _obj.begin(); i!=_obj.end(); i++) - if((*i)->GetGUID() == guid) - return (*i); + for(ObjectMap::iterator i = _obj.begin(); i!=_obj.end(); i++) + if(i->second->GetGUID() == guid) + return i->second; return NULL; } diff --git a/src/Client/World/ObjMgr.h b/src/Client/World/ObjMgr.h index 8dd981d..a085a4d 100644 --- a/src/Client/World/ObjMgr.h +++ b/src/Client/World/ObjMgr.h @@ -7,12 +7,16 @@ #include "Item.h" typedef std::vector ItemProtoList; -typedef std::list ObjectList; +typedef std::map ObjectMap; + +class PseuInstance; class ObjMgr { public: + ObjMgr(); ~ObjMgr(); + void SetInstance(PseuInstance*); void RemoveAll(void); // TODO: this needs to be called on SMSG_LOGOUT_COMPLETE once implemented. // Item Prototype functions @@ -29,11 +33,13 @@ public: void Add(Object*); void Remove(uint64); // remove all objects with that guid (should be only 1 object in total anyway) Object *GetObj(uint64 guid); + inline uint32 GetObjectCount(void) { return _obj.size(); } private: ItemProtoList _iproto; - ObjectList _obj; + ObjectMap _obj; std::vector _noitem; + PseuInstance *_instance; }; diff --git a/src/Client/World/Player.cpp b/src/Client/World/Player.cpp index cc19c0a..7047cda 100644 --- a/src/Client/World/Player.cpp +++ b/src/Client/World/Player.cpp @@ -23,9 +23,15 @@ void Player::Create(uint64 guid) MyCharacter::MyCharacter() : Player() { + DEBUG(logdebug("MyCharacter() constructor, this=0x%x",this)); SetTarget(0); } +MyCharacter::~MyCharacter() +{ + DEBUG(logdebug("~MyCharacter() destructor, this=0x%X guid="I64FMT,this,GetGUID())); // this _could_ crash if Player::Create(guid) wasnt called before! +} + void MyCharacter::SetActionButtons(WorldPacket &data) { diff --git a/src/Client/World/Player.h b/src/Client/World/Player.h index 19885cf..2c6093c 100644 --- a/src/Client/World/Player.h +++ b/src/Client/World/Player.h @@ -200,6 +200,7 @@ class MyCharacter : public Player { public: MyCharacter(); + ~MyCharacter(); void SetActionButtons(WorldPacket &data); void AddSpell(uint32 spellid, uint16 spellslot); diff --git a/src/Client/World/UpdateData.cpp b/src/Client/World/UpdateData.cpp index 7cc1791..9b631d6 100644 --- a/src/Client/World/UpdateData.cpp +++ b/src/Client/World/UpdateData.cpp @@ -30,134 +30,159 @@ void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket) WorldPacket wp; wp.SetOpcode(recvPacket.GetOpcode()); wp.append(z.contents(),z.size()); - + _HandleUpdateObjectOpcode(wp); } void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket) { - uint8 utype; - uint8 unk8; - uint32 usize, ublocks; - uint64 uguid; - recvPacket >> ublocks >> unk8; - while(recvPacket.rpos() < recvPacket.size()) - { - recvPacket >> utype; - switch(utype) - { - case UPDATETYPE_VALUES: - { + uint8 utype; + uint8 unk8; + uint32 usize, ublocks; + uint64 uguid; + recvPacket >> ublocks >> unk8; + while(recvPacket.rpos() < recvPacket.size()) + { + recvPacket >> utype; + switch(utype) + { + case UPDATETYPE_VALUES: + { uguid = recvPacket.GetPackedGuid(); _ValuesUpdate(uguid,recvPacket); - } - break; + } + break; - case UPDATETYPE_MOVEMENT: - { + case UPDATETYPE_MOVEMENT: + { recvPacket >> uguid; // the guid is NOT packed here! Object *obj = objmgr.GetObj(uguid); if(obj) - this->_MovementUpdate(obj->GetTypeId(),uguid,recvPacket); + this->_MovementUpdate(obj->GetTypeId(),uguid,recvPacket); else logcustom(2,RED,"Got UpdateObject_Movement for unknown object "I64FMT,uguid); - } - break; + } + break; - case UPDATETYPE_CREATE_OBJECT: - case UPDATETYPE_CREATE_OBJECT2: - { - uguid = recvPacket.GetPackedGuid(); - uint8 objtypeid; - recvPacket >> objtypeid; - logdebug("Create Object type %u with guid "I64FMT,objtypeid,uguid); + case UPDATETYPE_CREATE_OBJECT2: // will be sent when our very own character is created + case UPDATETYPE_CREATE_OBJECT: // will be sent on any other object creation + { + uguid = recvPacket.GetPackedGuid(); + uint8 objtypeid; + recvPacket >> objtypeid; + logdebug("Create Object type %u with guid "I64FMT,objtypeid,uguid); // dont create objects if already present in memory. // recreate every object except ourself! - if( uguid != GetGuid() && objmgr.GetObj(uguid)) + if(objmgr.GetObj(uguid)) { - logdev("- already exists, deleting old , creating new object"); - objmgr.Remove(uguid); - } - - switch(objtypeid) - { - case TYPEID_OBJECT: // no data to read - { - logerror("Recieved wrong UPDATETYPE_CREATE_OBJECT to create Object base type!"); - } - case TYPEID_ITEM: - { - Item *item = new Item(); - item->Create(uguid); - objmgr.Add(item); - break; - } - case TYPEID_CONTAINER: - { - Bag *bag = new Bag(); - bag->Create(uguid); - objmgr.Add(bag); - break; - } - case TYPEID_UNIT: - { - Unit *unit = new Unit(); - unit->Create(uguid); - objmgr.Add(unit); - break; - } - case TYPEID_PLAYER: + if(uguid != GetGuid()) { - Player *player = new Player(); - player->Create(uguid); - objmgr.Add(player); - break; + logdev("- already exists, deleting old , creating new object"); + objmgr.Remove(uguid); } - case TYPEID_GAMEOBJECT: + else { - GameObject *go = new GameObject(); - go->Create(uguid); - objmgr.Add(go); - break; - } - case TYPEID_CORPSE: - { - Corpse *corpse = new Corpse(); - corpse->Create(uguid); - objmgr.Add(corpse); - break; - } - case TYPEID_DYNAMICOBJECT: - { - DynamicObject *dobj = new DynamicObject(); - dobj->Create(uguid); - objmgr.Add(dobj); - break; + logdev("- already exists, but not deleted (has our current GUID)"); } } + // only if the obj didnt exist or was just deleted above, create it.... + if(!objmgr.GetObj(uguid)) + { + switch(objtypeid) + { + case TYPEID_OBJECT: // no data to read + { + logerror("Recieved wrong UPDATETYPE_CREATE_OBJECT to create Object base type!"); + } + case TYPEID_ITEM: + { + Item *item = new Item(); + item->Create(uguid); + objmgr.Add(item); + break; + } + case TYPEID_CONTAINER: + { + Bag *bag = new Bag(); + bag->Create(uguid); + objmgr.Add(bag); + break; + } + case TYPEID_UNIT: + { + Unit *unit = new Unit(); + unit->Create(uguid); + objmgr.Add(unit); + break; + } + case TYPEID_PLAYER: + { + Player *player = new Player(); + player->Create(uguid); + objmgr.Add(player); + break; + } + case TYPEID_GAMEOBJECT: + { + GameObject *go = new GameObject(); + go->Create(uguid); + objmgr.Add(go); + break; + } + case TYPEID_CORPSE: + { + Corpse *corpse = new Corpse(); + corpse->Create(uguid); + objmgr.Add(corpse); + break; + } + case TYPEID_DYNAMICOBJECT: + { + DynamicObject *dobj = new DynamicObject(); + dobj->Create(uguid); + objmgr.Add(dobj); + break; + } + } + } + else + { + logdebug("Obj "I64FMT" not created, already exists",uguid); + } + // ...regardless if it was freshly created or already present, update its values and stuff now... this->_MovementUpdate(objtypeid, uguid, recvPacket); this->_ValuesUpdate(uguid, recvPacket); + // ...and ask the server for eventually missing data. _QueryObjectInfo(uguid); - } - break; + // if our own character got finally created, we have successfully entered the world, + // and should have gotten all info about our char already. + // TODO: make called script function like "_enterworld" + //if(uguid==GetGuid()) + // _OnCharCreate(); + } + break; - case UPDATETYPE_OUT_OF_RANGE_OBJECTS: - recvPacket >> usize; - for(uint16 i=0;i> usize; + for(uint16 i=0;i> flags; - flags2 = 0; // not sure if its correct to set it to 0 (needs some starting flag?) + flags2 = 0; // not sure if its correct to set it to 0 (needs some starting flag?) - if(flags & UPDATEFLAG_LIVING) - { - recvPacket >> flags2 >> time; - } + if(flags & UPDATEFLAG_LIVING) + { + recvPacket >> flags2 >> time; + } - logdev("MovementUpdate TypeID=%u GUID="I64FMT" pObj=%X flags=%u flags2=%u",objtypeid,uguid,obj,flags,flags2); + logdev("MovementUpdate TypeID=%u GUID="I64FMT" pObj=%X flags=%u flags2=%u",objtypeid,uguid,obj,flags,flags2); - if(flags & UPDATEFLAG_HASPOSITION) - { - if(flags & UPDATEFLAG_TRANSPORT) - { - recvPacket >> unkfx >> unkfy >> unkfz >> o; // 3x (float)0 followed by orientation + if(flags & UPDATEFLAG_HASPOSITION) + { + if(flags & UPDATEFLAG_TRANSPORT) + { + recvPacket >> unkfx >> unkfy >> unkfz >> o; // 3x (float)0 followed by orientation logdev("TRANSPORT_FLOATS @ flags: x=%f y=%f z=%f o=%f",unkfx,unkfy,unkfz,o); - } - else - { - recvPacket >> x >> y >> z >> o; + } + else + { + recvPacket >> x >> y >> z >> o; logdev("FLOATS: x=%f y=%f z=%f o=%f",x,y,z,o); - } + } } if(flags & UPDATEFLAG_LIVING) - { - if(flags2 & FLAGS2_TRANSPORT) - { - recvPacket >> transguid >> tx >> ty >> tz >> to; - recvPacket >> unk32; // added in 2.0.3 + { + if(flags2 & FLAGS2_TRANSPORT) + { + recvPacket >> transguid >> tx >> ty >> tz >> to; + recvPacket >> unk32; // added in 2.0.3 logdev("TRANSPORT_FLOATS @ flags2: x=%f y=%f z=%f o=%f",tx,ty,tz,to); - } + } - recvPacket >> unk32; + recvPacket >> unk32; /* // not sure if this is/was correct, MaNGOS doesnt use it anymore - if(flags2 & 0x2000) // 0x2000 = ?? - { - recvPacket >> unkf >> unkf >> unkf >> unkf; - } + if(flags2 & 0x2000) // 0x2000 = ?? + { + recvPacket >> unkf >> unkf >> unkf >> unkf; + } */ - recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim; - recvPacket >> speedWalkBack >> speedFly >> speedFlyBack >> speedTurn; // fly added in 2.0.x - if(u) - { - u->SetPosition(x,y,z,o); - u->SetSpeed(MOVE_WALK,speedWalk); - u->SetSpeed(MOVE_RUN,speedRun); - u->SetSpeed(MOVE_SWIMBACK,speedSwimBack); - u->SetSpeed(MOVE_SWIM,speedSwim); - u->SetSpeed(MOVE_WALKBACK,speedWalkBack); - u->SetSpeed(MOVE_TURN,speedTurn); - u->SetSpeed(MOVE_FLY,speedFly); - u->SetSpeed(MOVE_FLYBACK,speedFlyBack); - } - else - { - logcustom(2,RED,"WorldSession::_MovementUpdate for unknown guid "I64FMT" typeid=%u",uguid,objtypeid); - } - } + recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim; + recvPacket >> speedWalkBack >> speedFly >> speedFlyBack >> speedTurn; // fly added in 2.0.x + if(u) + { + u->SetPosition(x,y,z,o); + u->SetSpeed(MOVE_WALK,speedWalk); + u->SetSpeed(MOVE_RUN,speedRun); + u->SetSpeed(MOVE_SWIMBACK,speedSwimBack); + u->SetSpeed(MOVE_SWIM,speedSwim); + u->SetSpeed(MOVE_WALKBACK,speedWalkBack); + u->SetSpeed(MOVE_TURN,speedTurn); + u->SetSpeed(MOVE_FLY,speedFly); + u->SetSpeed(MOVE_FLYBACK,speedFlyBack); + } + else + { + logcustom(2,RED,"WorldSession::_MovementUpdate for unknown guid "I64FMT" typeid=%u",uguid,objtypeid); + } + } - if(flags & UPDATEFLAG_ALL) - { - recvPacket >> unk32; - } + if(flags & UPDATEFLAG_ALL) + { + recvPacket >> unk32; + } - if(flags & UPDATEFLAG_HIGHGUID) - { - recvPacket >> higuid; // 2.0.6 - high guid was there, unk for 2.0.12 - // not sure if this is correct, MaNGOS sends 0 always. - //obj->SetUInt32Value(OBJECT_FIELD_GUID+1,higuid); // note that this sets only the high part of the guid - } + if(flags & UPDATEFLAG_HIGHGUID) + { + recvPacket >> higuid; // 2.0.6 - high guid was there, unk for 2.0.12 + // not sure if this is correct, MaNGOS sends 0 always. + //obj->SetUInt32Value(OBJECT_FIELD_GUID+1,higuid); // note that this sets only the high part of the guid + } - if(flags & UPDATEFLAG_FULLGUID) - { - // unused in mangos? but what if its needed? - // recvPacket >> fullguid; - } + if(flags & UPDATEFLAG_FULLGUID) + { + // unused in mangos? but what if its needed? + // recvPacket >> fullguid; + } - if(flags & UPDATEFLAG_TRANSPORT) - { - recvPacket >> transtime; // whats this used for? - } + if(flags & UPDATEFLAG_TRANSPORT) + { + recvPacket >> transtime; // whats this used for? + } } @@ -280,7 +305,7 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket) recvPacket.read((uint8*)updateMask, masksize); umask.SetMask(updateMask); //delete [] updateMask; // will be deleted at ~UpdateMask() !!!! - logdev("ValuesUpdate TypeId=%u GUID="I64FMT" pObj=%X Blocks=%u Masksize=%u",obj->GetTypeId(),uguid,obj,blockcount,masksize); + logdev("ValuesUpdate TypeId=%u GUID="I64FMT" pObj=%X Blocks=%u Masksize=%u",obj->GetTypeId(),uguid,obj,blockcount,masksize); for (uint32 i = 0; i < valuesCount; i++) { @@ -288,13 +313,13 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket) { recvPacket >> value; - // TODO: what to do here?! - /*if( obj->isType(TYPE_UNIT) && ( - i >= UNIT_FIELD_POWER1 && i <= UNIT_FIELD_MAXPOWER5 || - i >= UNIT_FIELD_BASEATTACKTIME && i <= UNIT_FIELD_RANGEDATTACKTIME || - i >= UNIT_FIELD_STR && i <= UNIT_FIELD_RESISTANCES + 6 ) - || obj->isType(TYPE_PLAYER) && - i >= PLAYER_FIELD_POSSTAT0 && i <= PLAYER_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6 ) + // TODO: what to do here?! + /*if( obj->isType(TYPE_UNIT) && ( + i >= UNIT_FIELD_POWER1 && i <= UNIT_FIELD_MAXPOWER5 || + i >= UNIT_FIELD_BASEATTACKTIME && i <= UNIT_FIELD_RANGEDATTACKTIME || + i >= UNIT_FIELD_STR && i <= UNIT_FIELD_RESISTANCES + 6 ) + || obj->isType(TYPE_PLAYER) && + i >= PLAYER_FIELD_POSSTAT0 && i <= PLAYER_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6 ) { obj->SetFloatValue(i, (float)value); } @@ -303,8 +328,8 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket) obj->SetUInt32Value(i, value); //} - // still nee to find out which values to interpret as floats - logdev("-> Field[%u] = %u",i,value); + // still need to find out which values to interpret as floats + logdev("-> Field[%u] = %u",i,value); } } } @@ -349,4 +374,4 @@ void WorldSession::_QueryObjectInfo(uint64 guid) //case... } } -} \ No newline at end of file +} diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index d113c72..212dfb0 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -13,16 +13,16 @@ #include "RealmSession.h" #include "WorldSession.h" -struct OpcodeHandler -{ - uint16 opcode; - void (WorldSession::*handler)(WorldPacket& recvPacket); +struct OpcodeHandler +{ + uint16 opcode; + void (WorldSession::*handler)(WorldPacket& recvPacket); }; WorldSession::WorldSession(PseuInstance *in) { - logdebug("-> Starting WorldSession from instance 0x%X",in); // should never output a null ptr + logdebug("-> Starting WorldSession 0x%X from instance 0x%X",this,in); // should never output a null ptr _instance = in; _mustdie=false; _logged=false; @@ -31,7 +31,10 @@ WorldSession::WorldSession(PseuInstance *in) _channels = new Channel(this); _world = NULL; _sh.SetAutoCloseSockets(false); + objmgr.SetInstance(in); //... + + DEBUG(logdebug("WorldSession 0x%X constructor finished",this)); } WorldSession::~WorldSession() @@ -50,6 +53,7 @@ WorldSession::~WorldSession() delete _socket; if(_world) delete _world; + DEBUG(logdebug("~WorldSession() this=0x%X _instance=0x%X",this,_instance)); } void WorldSession::Start(void) @@ -114,34 +118,34 @@ void WorldSession::Update(void) uint16 hpos; bool known=false; - while(pktQueue.size()) - { - WorldPacket *packet = pktQueue.next(); + while(pktQueue.size()) + { + WorldPacket *packet = pktQueue.next(); - for (hpos = 0; table[hpos].handler != NULL; hpos++) - { - if (table[hpos].opcode == packet->GetOpcode()) - { - known=true; - break; - } - } + for (hpos = 0; table[hpos].handler != NULL; hpos++) + { + if (table[hpos].opcode == packet->GetOpcode()) + { + known=true; + break; + } + } - bool hideOpcode = false; + bool hideOpcode = false; - // TODO: Maybe make table or something with all the frequently opcodes - if (packet->GetOpcode() == SMSG_MONSTER_MOVE) - { - hideOpcode = true; - } + // TODO: Maybe make table or something with all the frequently opcodes + if (packet->GetOpcode() == SMSG_MONSTER_MOVE) + { + hideOpcode = true; + } - if( (known && GetInstance()->GetConf()->showopcodes==1) - || ((!known) && GetInstance()->GetConf()->showopcodes==2) - || (GetInstance()->GetConf()->showopcodes==3) ) - { - if(!(GetInstance()->GetConf()->hidefreqopcodes && hideOpcode)) - logcustom(1,YELLOW,">> Opcode %u [%s] (%s, %u bytes)", packet->GetOpcode(), GetOpcodeName(packet->GetOpcode()), known ? "Known" : "UNKNOWN", packet->size()); - } + if( (known && GetInstance()->GetConf()->showopcodes==1) + || ((!known) && GetInstance()->GetConf()->showopcodes==2) + || (GetInstance()->GetConf()->showopcodes==3) ) + { + if(!(GetInstance()->GetConf()->hidefreqopcodes && hideOpcode)) + logcustom(1,YELLOW,">> Opcode %u [%s] (%s, %u bytes)", packet->GetOpcode(), GetOpcodeName(packet->GetOpcode()), known ? "Known" : "UNKNOWN", packet->size()); + } if(known) { @@ -156,14 +160,14 @@ void WorldSession::Update(void) } } - delete packet; + delete packet; known=false; - } + } _DoTimedActions(); if(_world) - _world->Update(); + _world->Update(); } @@ -200,16 +204,16 @@ OpcodeHandler *WorldSession::_GetOpcodeHandlerTable() const {MSG_MOVE_HEARTBEAT, &WorldSession::_HandleMovementOpcode}, {MSG_MOVE_FALL_LAND, &WorldSession::_HandleMovementOpcode}, - {MSG_MOVE_TELEPORT_ACK, &WorldSession::_HandleTelePortAckOpcode}, + {MSG_MOVE_TELEPORT_ACK, &WorldSession::_HandleTelePortAckOpcode}, {SMSG_COMPRESSED_UPDATE_OBJECT, &WorldSession::_HandleCompressedUpdateObjectOpcode}, - {SMSG_UPDATE_OBJECT, &WorldSession::_HandleUpdateObjectOpcode}, - {SMSG_CAST_RESULT, &WorldSession::_HandleCastResultOpcode}, + {SMSG_UPDATE_OBJECT, &WorldSession::_HandleUpdateObjectOpcode}, + {SMSG_CAST_RESULT, &WorldSession::_HandleCastResultOpcode}, {SMSG_ITEM_QUERY_SINGLE_RESPONSE, &WorldSession::_HandleItemQuerySingleResponseOpcode}, {SMSG_DESTROY_OBJECT, &WorldSession::_HandleDestroyObjectOpcode}, {SMSG_INITIAL_SPELLS, &WorldSession::_HandleInitialSpellsOpcode}, - {SMSG_LEARNED_SPELL, &WorldSession::_HandleLearnedSpellOpcode}, - {SMSG_REMOVED_SPELL, &WorldSession::_HandleLearnedSpellOpcode}, - {SMSG_CHANNEL_LIST, &WorldSession::_HandleChannelListOpcode}, + {SMSG_LEARNED_SPELL, &WorldSession::_HandleLearnedSpellOpcode}, + {SMSG_REMOVED_SPELL, &WorldSession::_HandleLearnedSpellOpcode}, + {SMSG_CHANNEL_LIST, &WorldSession::_HandleChannelListOpcode}, {SMSG_EMOTE, &WorldSession::_HandleEmoteOpcode}, {SMSG_TEXT_EMOTE, &WorldSession::_HandleTextEmoteOpcode}, {SMSG_NEW_WORLD, &WorldSession::_HandleNewWorldOpcode}, @@ -233,7 +237,7 @@ void WorldSession::_OnEnterWorld(void) _logged=true; GetInstance()->GetScripts()->variables.Set("@inworld","true"); GetInstance()->GetScripts()->RunScript("_enterworld",NULL); - + } } @@ -270,34 +274,34 @@ void WorldSession::_DoTimedActions(void) void WorldSession::_HandleAuthChallengeOpcode(WorldPacket& recvPacket) { std::string acc = stringToUpper(GetInstance()->GetConf()->accname); - uint32 serverseed; - recvPacket >> serverseed; - logdebug("Auth: serverseed=0x%X",serverseed); - Sha1Hash digest; - digest.UpdateData(acc); - uint32 unk=0; - digest.UpdateData((uint8*)&unk,sizeof(uint32)); - BigNumber clientseed; - clientseed.SetRand(8*4); - uint32 clientseed_uint32=clientseed.AsDword(); - digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32)); - digest.UpdateData((uint8*)&serverseed,sizeof(uint32)); - digest.UpdateBigNumbers(&(GetInstance()->GetSessionKey()),NULL); - digest.Finalize(); - WorldPacket auth; - auth<<(uint32)(GetInstance()->GetConf()->clientbuild)<> serverseed; + logdebug("Auth: serverseed=0x%X",serverseed); + Sha1Hash digest; + digest.UpdateData(acc); + uint32 unk=0; + digest.UpdateData((uint8*)&unk,sizeof(uint32)); + BigNumber clientseed; + clientseed.SetRand(8*4); + uint32 clientseed_uint32=clientseed.AsDword(); + digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32)); + digest.UpdateData((uint8*)&serverseed,sizeof(uint32)); + digest.UpdateBigNumbers(&(GetInstance()->GetSessionKey()),NULL); + digest.Finalize(); + WorldPacket auth; + auth<<(uint32)(GetInstance()->GetConf()->clientbuild)<InitCrypt(GetInstance()->GetSessionKey().AsByteArray(), 40); + _socket->InitCrypt(GetInstance()->GetSessionKey().AsByteArray(), 40); } @@ -306,12 +310,12 @@ void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket) uint8 errcode; recvPacket >> errcode; if(errcode==0xC){ - logdetail("World Authentication successful, preparing for char list request..."); + logdetail("World Authentication successful, preparing for char list request..."); WorldPacket pkt; pkt.SetOpcode(CMSG_CHAR_ENUM); - SendWorldPacket(pkt); + SendWorldPacket(pkt); } else { - logcritical("World Authentication failed, errcode=0x%X",(unsigned char)errcode); + logcritical("World Authentication failed, errcode=0x%X",(unsigned char)errcode); GetInstance()->SetError(); } } @@ -319,59 +323,60 @@ void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket) void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket) { uint8 num; - PlayerEnum plr[10]; // max characters per realm is 10 - uint8 dummy8; + PlayerEnum plr[10]; // max characters per realm is 10 + uint8 dummy8; - recvPacket >> num; - if(num==0){ - logerror("No chars found!"); - GetInstance()->SetError(); - return; - } - _LoadCache(); // we are about to login, so we need cache data - logdetail("W: Chars in list: %u\n",num); - for(unsigned int i=0;i> plr[i]._guid; - recvPacket >> plr[i]._name; - recvPacket >> plr[i]._race; - recvPacket >> plr[i]._class; - recvPacket >> plr[i]._gender; - recvPacket >> plr[i]._bytes1; - recvPacket >> plr[i]._bytes2; - recvPacket >> plr[i]._bytes3; - recvPacket >> plr[i]._bytes4; - recvPacket >> plr[i]._bytesx; - recvPacket >> plr[i]._level; - recvPacket >> plr[i]._zoneId; - recvPacket >> plr[i]._mapId; - recvPacket >> plr[i]._x; - recvPacket >> plr[i]._y; - recvPacket >> plr[i]._z; - recvPacket >> plr[i]._guildId; - recvPacket >> dummy8; - recvPacket >> plr[i]._flags; - recvPacket >> dummy8 >> dummy8 >> dummy8; - recvPacket >> plr[i]._petInfoId; - recvPacket >> plr[i]._petLevel; - recvPacket >> plr[i]._petFamilyId; - for(unsigned int inv=0;inv<20;inv++) + recvPacket >> num; + if(num==0){ + logerror("No chars found!"); + GetInstance()->SetError(); + return; + } + + logdetail("Chars in list: %u\n",num); + _LoadCache(); // we are about to login, so we need cache data + for(unsigned int i=0;i> plr[i]._guid; + recvPacket >> plr[i]._name; + recvPacket >> plr[i]._race; + recvPacket >> plr[i]._class; + recvPacket >> plr[i]._gender; + recvPacket >> plr[i]._bytes1; + recvPacket >> plr[i]._bytes2; + recvPacket >> plr[i]._bytes3; + recvPacket >> plr[i]._bytes4; + recvPacket >> plr[i]._bytesx; + recvPacket >> plr[i]._level; + recvPacket >> plr[i]._zoneId; + recvPacket >> plr[i]._mapId; + recvPacket >> plr[i]._x; + recvPacket >> plr[i]._y; + recvPacket >> plr[i]._z; + recvPacket >> plr[i]._guildId; + recvPacket >> dummy8; + recvPacket >> plr[i]._flags; + recvPacket >> dummy8 >> dummy8 >> dummy8; + recvPacket >> plr[i]._petInfoId; + recvPacket >> plr[i]._petLevel; + recvPacket >> plr[i]._petFamilyId; + for(unsigned int inv=0;inv<20;inv++) { - recvPacket >> plr[i]._items[inv].displayId >> plr[i]._items[inv].inventorytype; + recvPacket >> plr[i]._items[inv].displayId >> plr[i]._items[inv].inventorytype; } plrNameCache.AddInfo(plr[i]._guid, plr[i]._name); - } - bool char_found=false; + } + bool char_found=false; - for(unsigned int i=0;i 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); + GetDBMgr().GetAreaName(plr[i]._zoneId).c_str()); + 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); for(unsigned int inv=0;inv<20;inv++) { if(plr[i]._items[inv].displayId) @@ -379,66 +384,76 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket) } if(plr[i]._name==GetInstance()->GetConf()->charname) { - char_found=true; - _myGUID=plr[i]._guid; + char_found=true; + _myGUID=plr[i]._guid; GetInstance()->GetScripts()->variables.Set("@myrace",toString(plr[i]._race)); - } + } - } - if(!char_found){ - logerror("Character \"%s\" was not found on char list!",GetInstance()->GetConf()->charname.c_str()); - GetInstance()->SetError(); - return; - } else { - log("Entering World with Character \"%s\"...",GetInstance()->GetConf()->charname.c_str()); - // create the character and add it to the objmgr. - MyCharacter *my = new MyCharacter(); - my->Create(_myGUID); - objmgr.Add(my); + } + if(!char_found){ + logerror("Character \"%s\" was not found on char list!",GetInstance()->GetConf()->charname.c_str()); + GetInstance()->SetError(); + return; + } else { + log("Entering World with Character \"%s\"...",GetInstance()->GetConf()->charname.c_str()); + + // create the character and add it to the objmgr. + // note: this is the only object that has to stay in memory unless its explicitly deleted by the server! + // that means even if the server sends create object with that guid, do NOT recreate it!! + MyCharacter *my = new MyCharacter(); + my->Create(_myGUID); + objmgr.Add(my); // TODO: initialize the world here, and load required maps. // must remove appropriate code from _HandleLoginVerifyWorldOpcode() then!! - WorldPacket pkt(CMSG_PLAYER_LOGIN,8); - pkt << _myGUID; - SendWorldPacket(pkt); - } + WorldPacket pkt(CMSG_PLAYER_LOGIN,8); + pkt << _myGUID; + SendWorldPacket(pkt); + } } void WorldSession::_HandleSetProficiencyOpcode(WorldPacket& recvPacket) { - _OnEnterWorld(); + if(recvPacket.size()) + { + DEBUG( + logdebug("SetProficiency: Hexdump:"); + logdebug(toHexDump((uint8*)recvPacket.contents(),recvPacket.size(),true).c_str()); + ); + } } void WorldSession::_HandleAccountDataMD5Opcode(WorldPacket& recvPacket) { - _OnEnterWorld(); + // packet structure not yet known } void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) { uint8 type=0; - uint32 lang=0; - uint64 target_guid=0; - uint32 msglen=0; - std::string msg,channel=""; + uint32 lang=0; + uint64 target_guid=0; + uint32 msglen=0; + std::string msg,channel=""; bool isCmd=false; - recvPacket >> type >> lang; + recvPacket >> type >> lang; std::string langname = GetDBMgr().GetLangName(lang); const char* ln = langname.c_str(); - - if (type == CHAT_MSG_CHANNEL) + + if (type == CHAT_MSG_CHANNEL) { - recvPacket >> channel; // extract channel name + recvPacket >> channel; // extract channel name } - - recvPacket >> target_guid; + + recvPacket >> target_guid; std::string plrname; - if(target_guid){ + if(target_guid) + { plrname=plrNameCache.GetName(target_guid); if(plrname.empty()) { @@ -446,54 +461,54 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) plrname="Unknown Entity"; } } - GetInstance()->GetScripts()->variables.Set("@thismsg_name",plrname); - GetInstance()->GetScripts()->variables.Set("@thismsg",toString(target_guid)); - - - if(type == CHAT_MSG_SAY || type == CHAT_MSG_YELL || type == CHAT_MSG_PARTY) - recvPacket >> target_guid; - - recvPacket >> msglen >> msg; - if (type == CHAT_MSG_SYSTEM) + GetInstance()->GetScripts()->variables.Set("@thismsg_name",plrname); + GetInstance()->GetScripts()->variables.Set("@thismsg",toString(target_guid)); + + + if(type == CHAT_MSG_SAY || type == CHAT_MSG_YELL || type == CHAT_MSG_PARTY) + recvPacket >> target_guid; + + recvPacket >> msglen >> msg; + if (type == CHAT_MSG_SYSTEM) { - logcustom(0,WHITE,"SYSMSG: \"%s\"",msg.c_str()); - } + logcustom(0,WHITE,"SYSMSG: \"%s\"",msg.c_str()); + } else if (type==CHAT_MSG_WHISPER ) { - logcustom(0,WHITE,"WHISP: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"WHISP: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_CHANNEL ) { - logcustom(0,WHITE,"CHANNEL: [%s]: %s [%s]: %s",channel.c_str(),plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"CHANNEL: [%s]: %s [%s]: %s",channel.c_str(),plrname.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_SAY ) { - logcustom(0,WHITE,"CHAT: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"CHAT: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_YELL ) { - logcustom(0,WHITE,"CHAT: %s yells [%s]: %s ",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"CHAT: %s yells [%s]: %s ",plrname.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_WHISPER_INFORM ) { - logcustom(0,WHITE,"TO %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"TO %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_GUILD ) { - logcustom(0,WHITE,"GUILD: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"GUILD: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_PARTY ) { - logcustom(0,WHITE,"PARTY: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"PARTY: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_EMOTE ) { - logcustom(0,WHITE,"EMOTE: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"EMOTE [%s]: %s %s",ln,plrname.c_str(),msg.c_str()); } else { logcustom(0,WHITE,"UNK CHAT TYPE (%u): %s [%s]: %s",type,plrname.c_str(),ln,msg.c_str()); - } + } if(target_guid!=GetGuid() && msg.length()>1 && msg.at(0)=='-' && GetInstance()->GetConf()->allowgamecmd) isCmd=true; @@ -502,14 +517,14 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) if(type==CHAT_MSG_SAY && target_guid!=_myGUID && !isCmd) { // TODO: insert a good ChatAI here. - if (GetInstance()->GetConf()->enablechatai) - { - if(msg=="lol") + if (GetInstance()->GetConf()->enablechatai) + { + if(msg=="lol") SendChatMessage(CHAT_MSG_SAY,lang,"say \"lol\" if you have nothing else to say... lol xD",""); else if(msg.length()>4 && msg.find("you?")!=std::string::npos) SendChatMessage(CHAT_MSG_SAY,lang,GetInstance()->GetScripts()->variables.Get("@version").append(" -- i am a bot, made by False.Genesis, my master."),""); else if(msg=="hi") - SendChatMessage(CHAT_MSG_SAY,lang,"Hi, wadup?",""); + SendChatMessage(CHAT_MSG_SAY,lang,"Hi, wadup?",""); else if(msg.length()<12 && msg.find("wtf")!=std::string::npos) SendChatMessage(CHAT_MSG_SAY,lang,"Yeah, WTF is a good way to say you dont understand anything... :P",""); else if(msg.length()<15 && (msg.find("omg")!=std::string::npos || msg.find("omfg")!=std::string::npos) ) @@ -523,8 +538,8 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) if(isCmd) { - GetInstance()->GetScripts()->variables.Set("@thiscmd_name",plrname); - GetInstance()->GetScripts()->variables.Set("@thiscmd",toString(target_guid)); + GetInstance()->GetScripts()->variables.Set("@thiscmd_name",plrname); + GetInstance()->GetScripts()->variables.Set("@thiscmd",toString(target_guid)); std::string lin=msg.substr(1,msg.length()-1); try { @@ -534,12 +549,12 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) { SendChatMessage(CHAT_MSG_SAY,0,"Exception while trying to execute: [ "+lin+" ]",""); } - + } if(type==CHAT_MSG_WHISPER && (!isCmd) && target_guid!=GetGuid()) { GetInstance()->GetScripts()->variables.Set("@thiswhisper_name",plrname); - GetInstance()->GetScripts()->variables.Set("@thiswhisper",toString(target_guid)); + GetInstance()->GetScripts()->variables.Set("@thiswhisper",toString(target_guid)); GetInstance()->GetScripts()->variables.Set("@thiswhisper_lang",toString((uint64)lang)); GetInstance()->GetScripts()->RunScript("_onwhisper",NULL); } @@ -560,9 +575,12 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) pos++; } id = atoi(itemid.c_str()); - logdebug("Found Item in chat message: %u",id); - if(objmgr.GetItemProto(id)==NULL) - SendQueryItem(id,0); + if(id) + { + logdebug("Found Item in chat message: %u",id); + if(objmgr.GetItemProto(id)==NULL) + SendQueryItem(id,0); + } } } } @@ -636,35 +654,37 @@ void WorldSession::_HandleMovementOpcode(WorldPacket& recvPacket) void WorldSession::_HandleTelePortAckOpcode(WorldPacket& recvPacket) { - uint32 unk32,time; - uint64 guid; + uint32 unk32,time; + uint64 guid; - float x, y, z, o; + float x, y, z, o; guid = recvPacket.GetPackedGuid(); - recvPacket >> unk32 >> unk32 >> time >> x >> y >> z >> o >> unk32; + recvPacket >> unk32 >> unk32 >> time >> x >> y >> z >> o >> unk32; - logdetail("Got teleported, data: x: %f, y: %f, z: %f, o: %f, guid: "I64FMT, x, y, z, o, guid); + logdetail("Got teleported, data: x: %f, y: %f, z: %f, o: %f, guid: "I64FMT, x, y, z, o, guid); // TODO: put this into a capsule class later, that autodetects movement flags etc. - WorldPacket response; - response.SetOpcode(MSG_MOVE_FALL_LAND); - response << uint32(0) << (uint32)getMSTime(); // no flags; time correct? + WorldPacket response; + response.SetOpcode(MSG_MOVE_FALL_LAND); + response << uint32(0) << (uint32)getMSTime(); // no flags; time correct? response << x << y << z << o << uint32(0); - SendWorldPacket(response); + SendWorldPacket(response); if(_world) _world->UpdatePos(x,y); } void WorldSession::_HandleNewWorldOpcode(WorldPacket& recvPacket) { + DEBUG(logdebug("DEBUG: _HandleNewWorldOpcode() objs:%u mychar: ptr=0x%X, guid="I64FMT,objmgr.GetObjectCount(),GetMyChar(),GetMyChar()->GetGUID())); uint32 mapid; float x,y,z,o; // we assume we are NOT on a transport! // else we had to do the following before: // recvPacket >> tmapid >> tx >> ty >> tz >> to; recvPacket >> mapid >> x >> y >> z >> o; - GetMyChar()->ClearSpells(); // will be resent by server + if(GetMyChar()) + GetMyChar()->ClearSpells(); // will be resent by server // TODO: clear action buttons if(_world) delete _world; @@ -674,7 +694,7 @@ void WorldSession::_HandleNewWorldOpcode(WorldPacket& recvPacket) void WorldSession::_HandleChannelNotifyOpcode(WorldPacket& recvPacket) { - _channels->HandleNotifyOpcode(recvPacket); + _channels->HandleNotifyOpcode(recvPacket); } void WorldSession::_HandleCastResultOpcode(WorldPacket& recvPacket) @@ -695,26 +715,26 @@ void WorldSession::_HandleCastResultOpcode(WorldPacket& recvPacket) void WorldSession::_HandleInitialSpellsOpcode(WorldPacket& recvPacket) { - uint8 unk; - uint16 spellid,spellslot,count; - recvPacket >> unk >> count; - logdebug("Got initial spells list, %u spells.",count); - for(uint16 i = 0; i < count; i++) - { - recvPacket >> spellid >> spellslot; - logdebug("Initial Spell: id=%u slot=%u",spellid,spellslot); + uint8 unk; + uint16 spellid,spellslot,count; + recvPacket >> unk >> count; + logdebug("Got initial spells list, %u spells.",count); + for(uint16 i = 0; i < count; i++) + { + recvPacket >> spellid >> spellslot; + logdebug("Initial Spell: id=%u slot=%u",spellid,spellslot); - GetMyChar()->AddSpell(spellid, spellslot); - } + GetMyChar()->AddSpell(spellid, spellslot); + } } void WorldSession::_HandleLearnedSpellOpcode(WorldPacket& recvPacket) { - uint32 spellid; - recvPacket >> spellid; - GetMyChar()->AddSpell(spellid, 0); // other spells must be moved by +1 in slot? + uint32 spellid; + recvPacket >> spellid; + GetMyChar()->AddSpell(spellid, 0); // other spells must be moved by +1 in slot? - logdebug("Learned spell: id=%u",spellid); + logdebug("Learned spell: id=%u",spellid); } void WorldSession::_HandleRemovedSpellOpcode(WorldPacket& recvPacket) @@ -727,7 +747,7 @@ void WorldSession::_HandleRemovedSpellOpcode(WorldPacket& recvPacket) void WorldSession::_HandleChannelListOpcode(WorldPacket& recvPacket) { - _channels->HandleListRequest(recvPacket); + _channels->HandleListRequest(recvPacket); } void WorldSession::_HandleEmoteOpcode(WorldPacket& recvPacket) @@ -812,7 +832,7 @@ void WorldSession::_HandleTextEmoteOpcode(WorldPacket& recvPacket) target += "me"; else target += "one"; - + if(targeted) { target += "to"; @@ -857,6 +877,7 @@ void WorldSession::_HandleLoginVerifyWorldOpcode(WorldPacket& recvPacket) recvPacket >> m >> x >> y >> z >> o; // for now, init the world as soon as the server confirmed that we are where we are. logdebug("LoginVerifyWorld: map=%u x=%f y=%f z=%f o=%f",m,x,y,z,o); + _OnEnterWorld(); if(_world) delete _world; _world = new World(this); diff --git a/src/PseuWoW.vcproj b/src/PseuWoW.vcproj index 59ac995..e82068b 100644 --- a/src/PseuWoW.vcproj +++ b/src/PseuWoW.vcproj @@ -408,6 +408,18 @@ + + + + + + + + diff --git a/src/shared/MapTile.h b/src/shared/MapTile.h index 051cda9..a70f016 100644 --- a/src/shared/MapTile.h +++ b/src/shared/MapTile.h @@ -74,12 +74,13 @@ public: inline void SetTile(MapTile* tile, uint32 x, uint32 y) { SetTile(tile, y*64 + x); } inline void SetTile(MapTile* tile, uint32 pos) { - _tiles[pos] = tile; + if(pos < 4096) + _tiles[pos] = tile; } inline void UnloadMapTile(uint32 x, uint32 y) { UnloadMapTile(y*64 + x); } inline void UnloadMapTile(uint32 pos) { - if(_tiles[pos]) + if(pos < 4096 && _tiles[pos]) { delete _tiles[pos]; _tiles[pos] = NULL; @@ -88,12 +89,12 @@ public: inline bool TileExists(uint32 x, uint32 y) { return TileExists(y*64 + x); } inline bool TileExists(uint32 pos) { - return _hasTile[pos]; + return pos < 4096 ? _hasTile[pos] : false; } inline MapTile *GetTile(uint32 x, uint32 y) { return GetTile(y*64 + x); } inline MapTile *GetTile(uint32 pos) { - return _tiles[pos]; + return pos < 4096 ? _tiles[pos] : NULL; } void _DebugDump(void); diff --git a/src/shared/tools.cpp b/src/shared/tools.cpp index eb72aa8..ed6e965 100644 --- a/src/shared/tools.cpp +++ b/src/shared/tools.cpp @@ -105,7 +105,7 @@ std::deque GetFileList(std::string path) std::deque files; # ifndef _WIN32 // TODO: fix this function for linux if needed - const char *p = path.c_str(); + const char *p = path.c_str(); DIR * dirp; struct dirent * dp; dirp = opendir(p); @@ -130,15 +130,17 @@ std::deque GetFileList(std::string path) HANDLE hFil=FindFirstFile(p,&fil); if(hFil!=INVALID_HANDLE_VALUE) { - files.push_back(std::string(fil.cFileName)); - while(FindNextFile(hFil,&fil)) + if( !(fil.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) files.push_back(std::string(fil.cFileName)); + while(FindNextFile(hFil,&fil)) + { + if( !(fil.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) + files.push_back(std::string(fil.cFileName)); + } } # endif - while(files.size() && (files.front()=="." || files.front()=="..")) - files.pop_front(); return files; }