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.
This commit is contained in:
False.Genesis 2007-08-01 19:09:17 +00:00
parent 15e24961ce
commit 3100f68a30
31 changed files with 1315 additions and 824 deletions

View File

@ -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...

View File

@ -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: 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

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,6 +2,7 @@
//------------------------------------------------
#script=gc
#permission=0
//------------------------------------------------
// example script to write into channel "generalchat"
// usage: "gc bla bla..."

View File

@ -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:
// ==========

View File

@ -1,5 +1,3 @@
#permission=255
// EXECUTED EVERYTIME A WHISPER IS BEEING RECIEVED
// comment out the following line if you dont need it

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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 '"<<Set.defaultarg<<"' (not known)";
ws->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<std::string,unsigned char>::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);
}

View File

@ -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<uint64,DrawObject*>(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<uint64,DrawObject*> 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();
}

View File

@ -0,0 +1,27 @@
#ifndef DRAWOBJMGR_H
#define DRAWOBJMGR_H
#include <utility>
class DrawObject;
typedef std::map<uint64,DrawObject*> 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<uint64,ZThread::FastMutex> _del;
ZThread::LockedQueue<std::pair<uint64,DrawObject*>,ZThread::FastMutex > _add;
};
#endif

View File

@ -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)
{
}

View File

@ -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

View File

@ -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<s32>(_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<s32>(_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;
}

View File

@ -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;
};

View File

@ -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()
{
//...
//...
}

View File

@ -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<std::string,ZThread::FastMutex> _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
#endif

View File

@ -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;
}
}

View File

@ -3,36 +3,82 @@
#include <map>
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<std::string,std::string> 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<uint32,SCPField> SCPFieldMap;
typedef std::map<uint32,SCPField> 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);

View File

@ -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;
}

View File

@ -7,12 +7,16 @@
#include "Item.h"
typedef std::vector<ItemProto*> ItemProtoList;
typedef std::list<Object*> ObjectList;
typedef std::map<uint64,Object*> 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<uint32> _noitem;
PseuInstance *_instance;
};

View File

@ -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)
{

View File

@ -200,6 +200,7 @@ class MyCharacter : public Player
{
public:
MyCharacter();
~MyCharacter();
void SetActionButtons(WorldPacket &data);
void AddSpell(uint32 spellid, uint16 spellslot);

View File

@ -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;i++)
{
uguid = recvPacket.GetPackedGuid(); // not 100% sure if this is correct
logdebug("GUID "I64FMT" out of range",uguid);
objmgr.Remove(uguid);
}
break;
case UPDATETYPE_OUT_OF_RANGE_OBJECTS:
{
recvPacket >> usize;
for(uint16 i=0;i<usize;i++)
{
uguid = recvPacket.GetPackedGuid(); // not 100% sure if this is correct
logdebug("GUID "I64FMT" out of range",uguid);
objmgr.Remove(uguid);
}
}
break;
default:
logerror("UPDATE_OBJECT: Got unk updatetype 0x%X",utype);
logerror("UPDATE_OBJECT: Read %u / %u bytes, skipped rest",recvPacket.rpos(),recvPacket.size());
return;
default:
{
logerror("UPDATE_OBJECT: Got unk updatetype 0x%X",utype);
logerror("UPDATE_OBJECT: Read %u / %u bytes, skipped rest",recvPacket.rpos(),recvPacket.size());
return;
}
} // switch
} // while
@ -169,97 +194,97 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r
uint32 unk32,flags2,time,transtime,higuid;
float unkfx,unkfy,unkfz,x,y,z,o,tx,ty,tz,to;
uint64 transguid;
// uint64 fullguid; // see below
// uint64 fullguid; // see below
float speedWalk, speedRun, speedSwimBack, speedSwim, speedWalkBack, speedTurn, speedFly, speedFlyBack;
Object *obj = (Object*)objmgr.GetObj(uguid);
Unit *u = (Unit*)obj; // only use for Unit:: functions!!
Object *obj = (Object*)objmgr.GetObj(uguid);
Unit *u = (Unit*)obj; // only use for Unit:: functions!!
recvPacket >> 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...
}
}
}
}

View File

@ -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)<<unk<<acc<<clientseed_uint32;
auth.append(digest.GetDigest(),20);
// recvPacket << real_size
// recvPacket << ziped_UI_Plugins_Info
// TODO: add addon data, simulate no addons.
auth<<(uint32)0; // no addons? no idea, but seems to work. MaNGOS doesnt accept without this.
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)<<unk<<acc<<clientseed_uint32;
auth.append(digest.GetDigest(),20);
// recvPacket << real_size
// recvPacket << ziped_UI_Plugins_Info
// TODO: add addon data, simulate no addons.
auth<<(uint32)0; // no addons? no idea, but seems to work. MaNGOS doesnt accept without this.
auth.SetOpcode(CMSG_AUTH_SESSION);
SendWorldPacket(auth);
SendWorldPacket(auth);
// note that if the sessionkey/auth is wrong or failed, the server sends the following packet UNENCRYPTED!
// so its not 100% correct to init the crypt here, but it should do the job if authing was correct
_socket->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<num;i++){
recvPacket >> 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<num;i++){
recvPacket >> 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<num;i++){
logcustom(0,LGREEN,"## %s (%u) [%s/%s] Map: %s; Zone: %s",
for(unsigned int i=0;i<num;i++){
logcustom(0,LGREEN,"## %s (%u) [%s/%s] Map: %s; Area: %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());
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);
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);

View File

@ -408,6 +408,18 @@
<Filter
Name="GUI"
Filter="">
<File
RelativePath=".\Client\Gui\DrawObject.cpp">
</File>
<File
RelativePath=".\Client\Gui\DrawObject.h">
</File>
<File
RelativePath=".\Client\Gui\DrawObjMgr.cpp">
</File>
<File
RelativePath=".\Client\Gui\DrawObjMgr.h">
</File>
<File
RelativePath=".\Client\Gui\PseuGUI.cpp">
</File>

View File

@ -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);

View File

@ -105,7 +105,7 @@ std::deque<std::string> GetFileList(std::string path)
std::deque<std::string> 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<std::string> 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;
}